update Piwik to version 2.16 (fixes #91)
This commit is contained in:
parent
296343bf3b
commit
d885a4baa9
5833 changed files with 418860 additions and 226988 deletions
39
www/analytics/plugins/CoreConsole/Commands/ClearCaches.php
Normal file
39
www/analytics/plugins/CoreConsole/Commands/ClearCaches.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?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\Filesystem;
|
||||
use Piwik\Plugin\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
*/
|
||||
class ClearCaches extends ConsoleCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('core:clear-caches');
|
||||
$this->setAliases(array('cache:clear'));
|
||||
$this->setDescription('Cleares all caches. This command can be useful for instance after updating Piwik files manually.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute command like: ./console core:clear-caches
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
// Note: the logic for this command must be refactored in this helper function below.
|
||||
Filesystem::deleteAllCacheOnUpdate();
|
||||
|
||||
$this->writeSuccessMessage($output, array('Caches cleared'));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @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\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
*/
|
||||
class CodeCoverage extends ConsoleCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('tests:coverage');
|
||||
$this->setDescription('Run all phpunit tests and generate a combined code coverage');
|
||||
$this->addArgument('group', InputArgument::OPTIONAL, 'Run only a specific test group. Separate multiple groups by comma, for instance core,integration', '');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$phpCovPath = trim(shell_exec('which phpcov'));
|
||||
|
||||
if (empty($phpCovPath)) {
|
||||
|
||||
$output->writeln('phpcov not installed. please install pear.phpunit.de/phpcov.');
|
||||
return;
|
||||
}
|
||||
|
||||
$command = $this->getApplication()->find('tests:run');
|
||||
$arguments = array(
|
||||
'command' => 'tests:run',
|
||||
'--options' => sprintf('--coverage-php %s/tests/results/logs/%%group%%.cov', PIWIK_DOCUMENT_ROOT),
|
||||
);
|
||||
|
||||
$groups = $input->getArgument('group');
|
||||
if (!empty($groups)) {
|
||||
$arguments['group'] = $groups;
|
||||
} else {
|
||||
shell_exec(sprintf('rm %s/tests/results/logs/*.cov', PIWIK_DOCUMENT_ROOT));
|
||||
}
|
||||
|
||||
$inputObject = new ArrayInput($arguments);
|
||||
$inputObject->setInteractive($input->isInteractive());
|
||||
$command->run($inputObject, $output);
|
||||
|
||||
$command = 'phpcov';
|
||||
|
||||
// force xdebug usage for coverage options
|
||||
if (!extension_loaded('xdebug')) {
|
||||
|
||||
$output->writeln('<info>xdebug extension required for code coverage.</info>');
|
||||
|
||||
$output->writeln('<info>searching for xdebug extension...</info>');
|
||||
|
||||
$extensionDir = shell_exec('php-config --extension-dir');
|
||||
$xdebugFile = trim($extensionDir) . DIRECTORY_SEPARATOR . 'xdebug.so';
|
||||
|
||||
if (!file_exists($xdebugFile)) {
|
||||
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
|
||||
$xdebugFile = $dialog->askAndValidate($output, 'xdebug not found. Please provide path to xdebug.so', function($xdebugFile) {
|
||||
return file_exists($xdebugFile);
|
||||
});
|
||||
} else {
|
||||
|
||||
$output->writeln('<info>xdebug extension found in extension path.</info>');
|
||||
}
|
||||
|
||||
$output->writeln("<info>using $xdebugFile as xdebug extension.</info>");
|
||||
|
||||
$command = sprintf('php -d zend_extension=%s %s', $xdebugFile, $phpCovPath);
|
||||
}
|
||||
|
||||
shell_exec(sprintf('rm -rf %s/tests/results/coverage/*', PIWIK_DOCUMENT_ROOT));
|
||||
|
||||
passthru(sprintf('cd %1$s && %2$s --merge --html tests/results/coverage/ --whitelist ./core/ --whitelist ./plugins/ --add-uncovered %1$s/tests/results/logs/', PIWIK_DOCUMENT_ROOT, $command));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -9,7 +9,7 @@ namespace Piwik\Plugins\CoreConsole\Commands;
|
|||
|
||||
use Piwik\CronArchive;
|
||||
use Piwik\Plugin\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Piwik\Site;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
|
@ -23,33 +23,100 @@ class CoreArchiver extends ConsoleCommand
|
|||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($input->getOption('piwik-domain') && !$input->getOption('url')) {
|
||||
$_SERVER['argv'][] = '--url=' . $input->getOption('piwik-domain');
|
||||
}
|
||||
$archiver = self::makeArchiver($input->getOption('url'), $input);
|
||||
$archiver->main();
|
||||
}
|
||||
|
||||
include PIWIK_INCLUDE_PATH . '/misc/cron/archive.php';
|
||||
// also used by another console command
|
||||
public static function makeArchiver($url, InputInterface $input)
|
||||
{
|
||||
$archiver = new CronArchive();
|
||||
|
||||
$archiver->disableScheduledTasks = $input->getOption('disable-scheduled-tasks');
|
||||
$archiver->acceptInvalidSSLCertificate = $input->getOption("accept-invalid-ssl-certificate");
|
||||
$archiver->shouldArchiveAllSites = (bool) $input->getOption("force-all-websites");
|
||||
$archiver->shouldStartProfiler = (bool) $input->getOption("xhprof");
|
||||
$archiver->shouldArchiveSpecifiedSites = self::getSitesListOption($input, "force-idsites");
|
||||
$archiver->shouldSkipSpecifiedSites = self::getSitesListOption($input, "skip-idsites");
|
||||
$archiver->forceTimeoutPeriod = $input->getOption("force-timeout-for-periods");
|
||||
$archiver->shouldArchiveAllPeriodsSince = $input->getOption("force-all-periods");
|
||||
$archiver->restrictToDateRange = $input->getOption("force-date-range");
|
||||
$archiver->phpCliConfigurationOptions = $input->getOption("php-cli-options");
|
||||
|
||||
$restrictToPeriods = $input->getOption("force-periods");
|
||||
$restrictToPeriods = explode(',', $restrictToPeriods);
|
||||
$archiver->restrictToPeriods = array_map('trim', $restrictToPeriods);
|
||||
|
||||
$archiver->dateLastForced = $input->getOption('force-date-last-n');
|
||||
$archiver->concurrentRequestsPerWebsite = $input->getOption('concurrent-requests-per-website');
|
||||
|
||||
$archiver->disableSegmentsArchiving = $input->getOption('skip-all-segments');
|
||||
|
||||
$segmentIds = $input->getOption('force-idsegments');
|
||||
$segmentIds = explode(',', $segmentIds);
|
||||
$segmentIds = array_map('trim', $segmentIds);
|
||||
$archiver->setSegmentsToForceFromSegmentIds($segmentIds);
|
||||
|
||||
$archiver->setUrlToPiwik($url);
|
||||
|
||||
return $archiver;
|
||||
}
|
||||
|
||||
private static function getSitesListOption(InputInterface $input, $optionName)
|
||||
{
|
||||
return Site::getIdSitesFromIdSitesString($input->getOption($optionName));
|
||||
}
|
||||
|
||||
// This is reused by another console command
|
||||
static public function configureArchiveCommand(ConsoleCommand $command)
|
||||
public static function configureArchiveCommand(ConsoleCommand $command)
|
||||
{
|
||||
$command->setName('core:archive');
|
||||
$command->setDescription("Runs the CLI archiver. It is an important tool for general maintenance and to keep Piwik very fast.");
|
||||
$command->setHelp("* It is recommended to run the script with the option --piwik-domain=[piwik-server-url] only. Other options are not required.
|
||||
$command->setHelp("* It is recommended to run the script without any option.
|
||||
* This script should be executed every hour via crontab, or as a daemon.
|
||||
* You can also run it via http:// by specifying the Super User &token_auth=XYZ as a parameter ('Web Cron'),
|
||||
but it is recommended to run it via command line/CLI instead.
|
||||
* If you have any suggestion about this script, please let the team know at hello@piwik.org
|
||||
* If you have any suggestion about this script, please let the team know at feedback@piwik.org
|
||||
* Enjoy!");
|
||||
$command->addOption('url', null, InputOption::VALUE_REQUIRED, "Mandatory option as an alternative to '--piwik-domain'. Must be set to the Piwik base URL.\nFor example: --url=http://analytics.example.org/ or --url=https://example.org/piwik/");
|
||||
$command->addOption('force-all-websites', null, InputOption::VALUE_NONE, "If specified, the script will trigger archiving on all websites and all past dates.\nYou may use --force-all-periods=[seconds] to trigger archiving on those websites\nthat had visits in the last [seconds] seconds.");
|
||||
$command->addOption('force-all-periods', null, InputOption::VALUE_OPTIONAL, "Limits archiving to websites with some traffic in the last [seconds] seconds. \nFor example --force-all-periods=86400 will archive websites that had visits in the last 24 hours. \nIf [seconds] is not specified, all websites with visits in the last " . CronArchive::ARCHIVE_SITES_WITH_TRAFFIC_SINCE . "\n seconds (" . round(CronArchive::ARCHIVE_SITES_WITH_TRAFFIC_SINCE / 86400) . " days) will be archived.");
|
||||
$command->addOption('force-timeout-for-periods', null, InputOption::VALUE_OPTIONAL, "The current week/ current month/ current year will be processed at most every [seconds].\nIf not specified, defaults to " . CronArchive::SECONDS_DELAY_BETWEEN_PERIOD_ARCHIVES . ".");
|
||||
$command->addOption('force-date-last-n', null, InputOption::VALUE_REQUIRED, "This script calls the API with period=lastN. You can force the N in lastN by specifying this value.");
|
||||
$command->addOption('force-idsites', null, InputOption::VALUE_OPTIONAL, 'If specified, archiving will be processed only for these Sites Ids (comma separated)');
|
||||
$command->addOption('skip-idsites', null, InputOption::VALUE_OPTIONAL, 'If specified, archiving will be skipped for these websites (in case these website ids would have been archived).');
|
||||
$command->addOption('disable-scheduled-tasks', null, InputOption::VALUE_NONE, "Skips executing Scheduled tasks (sending scheduled reports, db optimization, etc.).");
|
||||
$command->addOption('xhprof', null, InputOption::VALUE_NONE, "Enables XHProf profiler for this archive.php run. Requires XHPRof (see tests/README.xhprof.md).");
|
||||
$command->addOption('accept-invalid-ssl-certificate', null, InputOption::VALUE_NONE, "It is _NOT_ recommended to use this argument. Instead, you should use a valid SSL certificate!\nIt can be useful if you specified --url=https://... or if you are using Piwik with force_ssl=1");
|
||||
$command->addOption('url', null, InputOption::VALUE_REQUIRED,
|
||||
"Forces the value of this option to be used as the URL to Piwik. \nIf your system does not support"
|
||||
. " archiving with CLI processes, you may need to set this in order for the archiving HTTP requests to use"
|
||||
. " the desired URLs.");
|
||||
$command->addOption('force-all-websites', null, InputOption::VALUE_NONE,
|
||||
"If specified, the script will trigger archiving on all websites.\nUse with --force-all-periods=[seconds] "
|
||||
. "to also process those websites that had visits in the last [seconds] seconds.\nLaunching several processes"
|
||||
. " with this option will make them share the list of sites to process.");
|
||||
$command->addOption('force-all-periods', null, InputOption::VALUE_OPTIONAL,
|
||||
"Limits archiving to websites with some traffic in the last [seconds] seconds. \nFor example "
|
||||
. "--force-all-periods=86400 will archive websites that had visits in the last 24 hours. \nIf [seconds] is "
|
||||
. "not specified, all websites with visits in the last " . CronArchive::ARCHIVE_SITES_WITH_TRAFFIC_SINCE
|
||||
. " seconds (" . round(CronArchive::ARCHIVE_SITES_WITH_TRAFFIC_SINCE / 86400) . " days) will be archived.");
|
||||
$command->addOption('force-timeout-for-periods', null, InputOption::VALUE_OPTIONAL,
|
||||
"The current week/ current month/ current year will be processed at most every [seconds].\nIf not "
|
||||
. "specified, defaults to " . CronArchive::SECONDS_DELAY_BETWEEN_PERIOD_ARCHIVES . ".");
|
||||
$command->addOption('skip-idsites', null, InputOption::VALUE_OPTIONAL,
|
||||
'If specified, archiving will be skipped for these websites (in case these website ids would have been archived).');
|
||||
$command->addOption('skip-all-segments', null, InputOption::VALUE_NONE,
|
||||
'If specified, all segments will be skipped during archiving.');
|
||||
$command->addOption('force-idsites', null, InputOption::VALUE_OPTIONAL,
|
||||
'If specified, archiving will be processed only for these Sites Ids (comma separated)');
|
||||
$command->addOption('force-periods', null, InputOption::VALUE_OPTIONAL,
|
||||
"If specified, archiving will be processed only for these Periods (comma separated eg. day,week,month,year,range)");
|
||||
$command->addOption('force-date-last-n', null, InputOption::VALUE_REQUIRED,
|
||||
"This script calls the API with period=lastN. You can force the N in lastN by specifying this value.");
|
||||
$command->addOption('force-date-range', null, InputOption::VALUE_OPTIONAL,
|
||||
"If specified, archiving will be processed only for periods included in this date range. Format: YYYY-MM-DD,YYYY-MM-DD");
|
||||
$command->addOption('force-idsegments', null, InputOption::VALUE_REQUIRED,
|
||||
'If specified, only these segments will be processed (if the segment should be applied to a site in the first place).'
|
||||
. "\nSpecify stored segment IDs, not the segments themselves, eg, 1,2,3. "
|
||||
. "\nNote: if identical segments exist w/ different IDs, they will both be skipped, even if you only supply one ID.");
|
||||
$command->addOption('concurrent-requests-per-website', null, InputOption::VALUE_OPTIONAL,
|
||||
"When processing a website and its segments, number of requests to process in parallel", CronArchive::MAX_CONCURRENT_API_REQUESTS);
|
||||
$command->addOption('disable-scheduled-tasks', null, InputOption::VALUE_NONE,
|
||||
"Skips executing Scheduled tasks (sending scheduled reports, db optimization, etc.).");
|
||||
$command->addOption('accept-invalid-ssl-certificate', null, InputOption::VALUE_NONE,
|
||||
"It is _NOT_ recommended to use this argument. Instead, you should use a valid SSL certificate!\nIt can be "
|
||||
. "useful if you specified --url=https://... or if you are using Piwik with force_ssl=1");
|
||||
$command->addOption('php-cli-options', null, InputOption::VALUE_OPTIONAL, 'Forwards the PHP configuration options to the PHP CLI command. For example "-d memory_limit=8G". Note: These options are only applied if the archiver actually uses CLI and not HTTP.', $default = '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
<?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\Config;
|
||||
use Piwik\Filesystem;
|
||||
use Piwik\Plugin\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
*/
|
||||
class DevelopmentEnable extends ConsoleCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('development:enable');
|
||||
$this->setAliases(array('development:disable'));
|
||||
$this->setDescription('Enable or disable development mode. See config/global.ini.php in section [Development] for more information');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$commandName = $input->getFirstArgument();
|
||||
$enable = (false !== strpos($commandName, 'enable'));
|
||||
|
||||
$config = Config::getInstance();
|
||||
$development = $config->Development;
|
||||
|
||||
if ($enable) {
|
||||
$development['enabled'] = 1;
|
||||
$development['disable_merged_assets'] = 1;
|
||||
$message = 'Development mode enabled';
|
||||
} else {
|
||||
$development['enabled'] = 0;
|
||||
$development['disable_merged_assets'] = 0;
|
||||
$message = 'Development mode disabled';
|
||||
}
|
||||
|
||||
$config->Development = $development;
|
||||
$config->forceSave();
|
||||
|
||||
Filesystem::deleteAllCacheOnUpdate();
|
||||
|
||||
$this->writeSuccessMessage($output, array($message));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,20 +1,26 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* 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\Development;
|
||||
use Piwik\Plugin\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ManageTestFiles extends ConsoleCommand
|
||||
class DevelopmentManageTestFiles extends ConsoleCommand
|
||||
{
|
||||
public function isEnabled()
|
||||
{
|
||||
return Development::isEnabled();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('development:test-files');
|
||||
|
|
@ -42,7 +48,7 @@ class ManageTestFiles extends ConsoleCommand
|
|||
{
|
||||
$file = $input->getOption('file');
|
||||
|
||||
$prefix = PIWIK_INCLUDE_PATH . '/tests/PHPUnit/Integration/processed/';
|
||||
$prefix = PIWIK_INCLUDE_PATH . '/tests/PHPUnit/System/processed/';
|
||||
$guesses = array(
|
||||
'/' . $file,
|
||||
$prefix . $file,
|
||||
|
|
@ -55,6 +61,6 @@ class ManageTestFiles extends ConsoleCommand
|
|||
}
|
||||
}
|
||||
|
||||
copy($file, PIWIK_INCLUDE_PATH . '/tests/PHPUnit/Integration/expected/' . basename($file));
|
||||
copy($file, PIWIK_INCLUDE_PATH . '/tests/PHPUnit/System/expected/' . basename($file));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<?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\Common;
|
||||
use Piwik\Container\StaticContainer;
|
||||
use Piwik\Decompress\Tar;
|
||||
use Piwik\Development;
|
||||
use Piwik\Http;
|
||||
use Piwik\Plugin\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class DevelopmentSyncProcessedSystemTests extends ConsoleCommand
|
||||
{
|
||||
private $targetDir = 'tests/PHPUnit/System/processed';
|
||||
|
||||
public function isEnabled()
|
||||
{
|
||||
return Development::isEnabled();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('development:sync-system-test-processed');
|
||||
$this->setDescription('For Piwik core devs. Copies processed system tests from travis artifacts to ' . $this->targetDir);
|
||||
$this->addArgument('buildnumber', InputArgument::REQUIRED, 'Travis build number you want to sync, eg "14820".');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$buildNumber = $input->getArgument('buildnumber');
|
||||
$targetDir = PIWIK_INCLUDE_PATH . '/' . dirname($this->targetDir);
|
||||
$tmpDir = StaticContainer::get('path.tmp');
|
||||
|
||||
$this->validate($buildNumber, $targetDir, $tmpDir);
|
||||
|
||||
if (Common::stringEndsWith($buildNumber, '.1')) {
|
||||
// eg make '14820.1' to '14820' to be backwards compatible
|
||||
$buildNumber = substr($buildNumber, 0, -2);
|
||||
}
|
||||
|
||||
$filename = sprintf('system.%s.tar.bz2', $buildNumber);
|
||||
$urlBase = sprintf('http://builds-artifacts.piwik.org/piwik/piwik/%s', $filename);
|
||||
$tests = Http::sendHttpRequest($urlBase, $timeout = 120);
|
||||
|
||||
$tarFile = $tmpDir . $filename;
|
||||
file_put_contents($tarFile, $tests);
|
||||
|
||||
$tar = new Tar($tarFile, 'bz2');
|
||||
$tar->extract($targetDir);
|
||||
|
||||
$this->writeSuccessMessage($output, array(
|
||||
'All processed system test results were copied to <comment>' . $this->targetDir . '</comment>',
|
||||
'Compare them with the expected test results and commit them if needed.'
|
||||
));
|
||||
|
||||
unlink($tarFile);
|
||||
}
|
||||
|
||||
private function validate($buildNumber, $targetDir, $tmpDir)
|
||||
{
|
||||
if (empty($buildNumber)) {
|
||||
throw new \InvalidArgumentException('Missing build number.');
|
||||
}
|
||||
|
||||
if (!is_writable($targetDir)) {
|
||||
throw new \RuntimeException('Target dir is not writable: ' . $targetDir);
|
||||
}
|
||||
|
||||
if (!is_writable($tmpDir)) {
|
||||
throw new \RuntimeException('Tempdir is not writable: ' . $tmpDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
<?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 Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
*/
|
||||
class GenerateAngularDirective extends GeneratePluginBase
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('generate:angular-directive')
|
||||
->setDescription('Generates a template for an AngularJS directive')
|
||||
->addOption('pluginname', null, InputOption::VALUE_REQUIRED, 'The name of an existing plugin')
|
||||
->addOption('directive', null, InputOption::VALUE_REQUIRED, 'The name of the directive you want to create.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginName = $this->getPluginName($input, $output);
|
||||
$directive = $this->getDirectiveName($input, $output);
|
||||
$pluginPath = $this->getPluginPath($pluginName);
|
||||
|
||||
$directiveLower = $this->getDirectiveComponentName($directive);
|
||||
|
||||
$targetDir = $pluginPath . '/angularjs/' . $directiveLower;
|
||||
|
||||
if (is_dir($targetDir) || file_exists($targetDir)) {
|
||||
throw new \Exception('The AngularJS directive ' . $directiveLower . ' already exists in plugin ' . $pluginName);
|
||||
}
|
||||
|
||||
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
|
||||
$replace = array(
|
||||
'ExamplePlugin' => $pluginName,
|
||||
'directive-component' => $directiveLower,
|
||||
'componentClass' => lcfirst($directive),
|
||||
'componentAs' => lcfirst($directive),
|
||||
'component' => $directiveLower,
|
||||
'Component' => $directive
|
||||
);
|
||||
|
||||
$componentPath = '/angularjs/directive-component';
|
||||
|
||||
$whitelistFiles = array(
|
||||
'/angularjs',
|
||||
$componentPath,
|
||||
$componentPath . '/component.controller.js',
|
||||
$componentPath . '/component.directive.html',
|
||||
$componentPath . '/component.directive.js',
|
||||
$componentPath . '/component.directive.less',
|
||||
);
|
||||
|
||||
$this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles);
|
||||
|
||||
$replacedBasePath = '/angularjs/' . $directiveLower . '/' . $directiveLower;
|
||||
$js1 = $replacedBasePath . '.controller.js';
|
||||
$js2 = $replacedBasePath . '.directive.js';
|
||||
$less1 = $replacedBasePath . '.directive.less';
|
||||
|
||||
$this->writeSuccessMessage($output, array(
|
||||
sprintf('AngularJS directive "%s" for plugin "%s" in "%s" generated', $directive, $pluginName, $targetDir),
|
||||
sprintf('In <comment>%1$s/%2$s.php</comment> you should now require the JS files', $pluginPath, $pluginName),
|
||||
sprintf('<comment>%1$s%2$s</comment>, <comment>%1$s%3$s</comment>', $pluginPath, $js1, $js2),
|
||||
sprintf('and the less file <comment>%1$s%2$s</comment>.', $pluginPath, $less1),
|
||||
'If you are not familiar with this have a look at <comment>http://developer.piwik.org/guides/working-with-piwiks-ui</comment>'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert MyComponentName => my-component-name
|
||||
* @param string $directiveCamelCase
|
||||
* @return string
|
||||
*/
|
||||
protected function getDirectiveComponentName($directiveCamelCase)
|
||||
{
|
||||
return strtolower(preg_replace('/([a-zA-Z])(?=[A-Z])/', '$1-', $directiveCamelCase));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return string
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function getDirectiveName(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$testname = $input->getOption('directive');
|
||||
|
||||
$validate = function ($testname) {
|
||||
if (empty($testname)) {
|
||||
throw new \InvalidArgumentException('You have to enter a name for the directive');
|
||||
}
|
||||
|
||||
if (!ctype_alnum($testname)) {
|
||||
throw new \InvalidArgumentException('Only alphanumeric characters are allowed as a directive name. Use CamelCase if the name of your directive contains multiple words.');
|
||||
}
|
||||
|
||||
return $testname;
|
||||
};
|
||||
|
||||
if (empty($testname)) {
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
$testname = $dialog->askAndValidate($output, 'Enter the name of the directive you want to create: ', $validate);
|
||||
} else {
|
||||
$validate($testname);
|
||||
}
|
||||
|
||||
$testname = ucfirst($testname);
|
||||
|
||||
return $testname;
|
||||
}
|
||||
|
||||
protected function getPluginName(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginNames = $this->getPluginNames();
|
||||
$invalidName = 'You have to enter the name of an existing plugin';
|
||||
|
||||
return $this->askPluginNameAndValidate($input, $output, $pluginNames, $invalidName);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -27,6 +27,7 @@ class GenerateApi extends GeneratePluginBase
|
|||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginName = $this->getPluginName($input, $output);
|
||||
$this->checkAndUpdateRequiredPiwikVersion($pluginName, $output);
|
||||
|
||||
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
|
||||
$replace = array('ExamplePlugin' => $pluginName);
|
||||
|
|
@ -45,7 +46,7 @@ class GenerateApi extends GeneratePluginBase
|
|||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
* @throws \RunTimeException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getPluginName(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
<?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 Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
*/
|
||||
class GenerateArchiver extends GeneratePluginBase
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('generate:archiver')
|
||||
->setDescription('Adds an Archiver to an existing plugin')
|
||||
->addOption('pluginname', null, InputOption::VALUE_REQUIRED, 'The name of an existing plugin which does not have an Archiver yet');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginName = $this->getPluginName($input, $output);
|
||||
$this->checkAndUpdateRequiredPiwikVersion($pluginName, $output);
|
||||
|
||||
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
|
||||
$replace = array('ExamplePlugin' => $pluginName, 'EXAMPLEPLUGIN' => strtoupper($pluginName));
|
||||
$whitelistFiles = array('/Archiver.php');
|
||||
|
||||
$this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles);
|
||||
|
||||
$this->writeSuccessMessage($output, array(
|
||||
sprintf('Archiver.php for %s generated.', $pluginName),
|
||||
'You can now start implementing Archiver methods',
|
||||
'Enjoy!'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getPluginName(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginNames = $this->getPluginNamesHavingNotSpecificFile('Archiver.php');
|
||||
$invalidName = 'You have to enter the name of an existing plugin which does not already have an Archiver';
|
||||
|
||||
return $this->askPluginNameAndValidate($input, $output, $pluginNames, $invalidName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
namespace Piwik\Plugins\CoreConsole\Commands;
|
||||
|
||||
use Piwik\Common;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
|
@ -29,12 +27,16 @@ class GenerateCommand extends GeneratePluginBase
|
|||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginName = $this->getPluginName($input, $output);
|
||||
$pluginName = $this->getPluginName($input, $output);
|
||||
$this->checkAndUpdateRequiredPiwikVersion($pluginName, $output);
|
||||
|
||||
$commandName = $this->getCommandName($input, $output);
|
||||
|
||||
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExampleCommand';
|
||||
$replace = array(
|
||||
'ExampleCommandDescription' => $commandName,
|
||||
'ExampleCommand' => $pluginName,
|
||||
'examplecommand:helloworld' => strtolower($pluginName) . ':' . $this->buildCommandName($commandName),
|
||||
'examplecommand' => strtolower($pluginName),
|
||||
'HelloWorld' => $commandName,
|
||||
'helloworld' => strtolower($commandName)
|
||||
|
|
@ -49,11 +51,20 @@ class GenerateCommand extends GeneratePluginBase
|
|||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert MyComponentName => my-component-name
|
||||
* @param string $commandNameCamelCase
|
||||
* @return string
|
||||
*/
|
||||
protected function buildCommandName($commandNameCamelCase)
|
||||
{
|
||||
return strtolower(preg_replace('/([a-zA-Z])(?=[A-Z])/', '$1-', $commandNameCamelCase));
|
||||
}
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return string
|
||||
* @throws \RunTimeException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function getCommandName(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
|
@ -64,12 +75,16 @@ class GenerateCommand extends GeneratePluginBase
|
|||
throw new \InvalidArgumentException('You have to enter a command name');
|
||||
}
|
||||
|
||||
if (!ctype_alnum($testname)) {
|
||||
throw new \InvalidArgumentException('Only alphanumeric characters are allowed as a command name. Use CamelCase if the name of your command contains multiple words.');
|
||||
}
|
||||
|
||||
return $testname;
|
||||
};
|
||||
|
||||
if (empty($testname)) {
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
$testname = $dialog->askAndValidate($output, 'Enter the name of the command: ', $validate);
|
||||
$testname = $dialog->askAndValidate($output, 'Enter the name of the command (CamelCase): ', $validate);
|
||||
} else {
|
||||
$validate($testname);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -27,6 +27,7 @@ class GenerateController extends GeneratePluginBase
|
|||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginName = $this->getPluginName($input, $output);
|
||||
$this->checkAndUpdateRequiredPiwikVersion($pluginName, $output);
|
||||
|
||||
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
|
||||
$replace = array('ExamplePlugin' => $pluginName);
|
||||
|
|
@ -45,7 +46,7 @@ class GenerateController extends GeneratePluginBase
|
|||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
* @throws \RunTimeException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getPluginName(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
|
|
|||
259
www/analytics/plugins/CoreConsole/Commands/GenerateDimension.php
Normal file
259
www/analytics/plugins/CoreConsole/Commands/GenerateDimension.php
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
<?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\Common;
|
||||
use Piwik\DbHelper;
|
||||
use Piwik\Plugin\Report;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class GenerateDimension extends GeneratePluginBase
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('generate:dimension')
|
||||
->setDescription('Adds a new dimension to an existing plugin. This allows you to persist new values during tracking.')
|
||||
->addOption('pluginname', null, InputOption::VALUE_REQUIRED, 'The name of an existing plugin which does not have a menu defined yet')
|
||||
->addOption('type', null, InputOption::VALUE_REQUIRED, 'Whether you want to create a "Visit", an "Action" or a "Conversion" dimension')
|
||||
->addOption('dimensionname', null, InputOption::VALUE_REQUIRED, 'A human readable name of the dimension which will be for instance visible in the UI')
|
||||
->addOption('columnname', null, InputOption::VALUE_REQUIRED, 'The name of the column in the MySQL database the dimension will be stored under')
|
||||
->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);
|
||||
$this->checkAndUpdateRequiredPiwikVersion($pluginName, $output);
|
||||
|
||||
$type = $this->getDimensionType($input, $output);
|
||||
$dimensionName = $this->getDimensionName($input, $output);
|
||||
|
||||
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/ExampleTracker';
|
||||
$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,
|
||||
'ExampleTracker_DimensionName' => $translatedDimensionName,
|
||||
'ExampleTracker' => $pluginName,
|
||||
);
|
||||
|
||||
$whitelistFiles = array('/Columns');
|
||||
|
||||
if ('visit' == $type) {
|
||||
$whitelistFiles[] = '/Columns/ExampleVisitDimension.php';
|
||||
} elseif ('action' == $type) {
|
||||
$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');
|
||||
}
|
||||
|
||||
$this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles);
|
||||
|
||||
$this->writeSuccessMessage($output, array(
|
||||
sprintf('Columns/%s.php for %s generated.', ucfirst($dimensionClassName), $pluginName),
|
||||
'You should now implement the events within this file',
|
||||
'Enjoy!'
|
||||
));
|
||||
}
|
||||
|
||||
private function getDimensionClassName($dimensionName)
|
||||
{
|
||||
$dimensionName = trim($dimensionName);
|
||||
$dimensionName = str_replace(' ', '', $dimensionName);
|
||||
$dimensionName = preg_replace("/[^A-Za-z0-9]/", '', $dimensionName);
|
||||
|
||||
$dimensionName = ucfirst($dimensionName);
|
||||
|
||||
return $dimensionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getDimensionName(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$validate = function ($dimensionName) {
|
||||
if (empty($dimensionName)) {
|
||||
throw new \InvalidArgumentException('Please enter the name of your dimension');
|
||||
}
|
||||
|
||||
if (preg_match("/[^A-Za-z0-9 ]/", $dimensionName)) {
|
||||
throw new \InvalidArgumentException('Only alpha numerical characters and whitespaces are allowed');
|
||||
}
|
||||
|
||||
return $dimensionName;
|
||||
};
|
||||
|
||||
$dimensionName = $input->getOption('dimensionname');
|
||||
|
||||
if (empty($dimensionName)) {
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
$dimensionName = $dialog->askAndValidate($output, 'Enter a human readable name of your dimension, for instance "Browser": ', $validate);
|
||||
} else {
|
||||
$validate($dimensionName);
|
||||
}
|
||||
|
||||
$dimensionName = ucfirst($dimensionName);
|
||||
|
||||
return $dimensionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @param string $type
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getColumnName(InputInterface $input, OutputInterface $output, $type)
|
||||
{
|
||||
$validate = function ($columnName) use ($type) {
|
||||
if (empty($columnName)) {
|
||||
throw new \InvalidArgumentException('Please enter the name of the dimension column');
|
||||
}
|
||||
|
||||
if (preg_match("/[^A-Za-z0-9_ ]/", $columnName)) {
|
||||
throw new \InvalidArgumentException('Only alpha numerical characters, underscores and whitespaces are allowed');
|
||||
}
|
||||
|
||||
if ('visit' == $type) {
|
||||
$columns = array_keys(DbHelper::getTableColumns(Common::prefixTable('log_visit')));
|
||||
} elseif ('action' == $type) {
|
||||
$columns = array_keys(DbHelper::getTableColumns(Common::prefixTable('log_link_visit_action')));
|
||||
} elseif ('conversion' == $type) {
|
||||
$columns = array_keys(DbHelper::getTableColumns(Common::prefixTable('log_conversion')));
|
||||
} else {
|
||||
$columns = array();
|
||||
}
|
||||
|
||||
foreach ($columns as $column) {
|
||||
if (strtolower($column) === strtolower($columnName)) {
|
||||
throw new \InvalidArgumentException('This column name is already in use.');
|
||||
}
|
||||
}
|
||||
|
||||
return $columnName;
|
||||
};
|
||||
|
||||
$columnName = $input->getOption('columnname');
|
||||
|
||||
if (empty($columnName)) {
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
$columnName = $dialog->askAndValidate($output, 'Enter the name of the column under which it should be stored in the MySQL database, for instance "visit_total_time": ', $validate);
|
||||
} else {
|
||||
$validate($columnName);
|
||||
}
|
||||
|
||||
return $columnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getColumnType(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$validate = function ($columnType) {
|
||||
if (empty($columnType)) {
|
||||
throw new \InvalidArgumentException('Please enter the type of the dimension column');
|
||||
}
|
||||
|
||||
return $columnType;
|
||||
};
|
||||
|
||||
$columnType = $input->getOption('columntype');
|
||||
|
||||
if (empty($columnType)) {
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
$columnType = $dialog->askAndValidate($output, 'Enter the type of the column under which it should be stored in the MySQL database, for instance "VARCHAR(255) NOT NULL": ', $validate);
|
||||
} else {
|
||||
$validate($columnType);
|
||||
}
|
||||
|
||||
return $columnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getDimensionType(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$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) . '). Choose "non-tracking-dimension" if you only need a blank dimension having a name: ');
|
||||
}
|
||||
|
||||
return $type;
|
||||
};
|
||||
|
||||
$type = $input->getOption('type');
|
||||
|
||||
if (empty($type)) {
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
$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);
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
}
|
||||
59
www/analytics/plugins/CoreConsole/Commands/GenerateMenu.php
Normal file
59
www/analytics/plugins/CoreConsole/Commands/GenerateMenu.php
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?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 Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
*/
|
||||
class GenerateMenu extends GeneratePluginBase
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('generate:menu')
|
||||
->setDescription('Adds a plugin menu class to an existing plugin')
|
||||
->addOption('pluginname', null, InputOption::VALUE_REQUIRED, 'The name of an existing plugin which does not have a menu defined yet');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginName = $this->getPluginName($input, $output);
|
||||
$this->checkAndUpdateRequiredPiwikVersion($pluginName, $output);
|
||||
|
||||
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
|
||||
$replace = array('ExamplePlugin' => $pluginName);
|
||||
$whitelistFiles = array('/Menu.php');
|
||||
|
||||
$this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles);
|
||||
|
||||
$this->writeSuccessMessage($output, array(
|
||||
sprintf('Menu.php for %s generated.', $pluginName),
|
||||
'You can now start defining your plugin menu',
|
||||
'Enjoy!'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getPluginName(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginNames = $this->getPluginNamesHavingNotSpecificFile('Menu.php');
|
||||
$invalidName = 'You have to enter the name of an existing plugin which does not already have a menu defined';
|
||||
|
||||
return $this->askPluginNameAndValidate($input, $output, $pluginNames, $invalidName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -9,8 +9,10 @@
|
|||
|
||||
namespace Piwik\Plugins\CoreConsole\Commands;
|
||||
|
||||
|
||||
use Piwik\Filesystem;
|
||||
use Piwik\Plugins\ExamplePlugin\ExamplePlugin;
|
||||
use Piwik\Version;
|
||||
use Piwik\Plugin;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
|
@ -28,25 +30,29 @@ class GeneratePlugin extends GeneratePluginBase
|
|||
->addOption('name', null, InputOption::VALUE_REQUIRED, 'Plugin name ([a-Z0-9_-])')
|
||||
->addOption('description', null, InputOption::VALUE_REQUIRED, 'Plugin description, max 150 characters')
|
||||
->addOption('pluginversion', null, InputOption::VALUE_OPTIONAL, 'Plugin version')
|
||||
->addOption('full', null, InputOption::VALUE_OPTIONAL, 'If a value is set, an API and a Controller will be created as well. Option is only available for creating plugins, not for creating themes.');
|
||||
->addOption('overwrite', null, InputOption::VALUE_NONE, 'Generate even if plugin directory already exists.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$isTheme = $this->isTheme($input);
|
||||
$pluginName = $this->getPluginName($input, $output);
|
||||
$description = $this->getPluginDescription($input, $output);
|
||||
$version = $this->getPluginVersion($input, $output);
|
||||
$createFullPlugin = !$isTheme && $this->getCreateFullPlugin($input, $output);
|
||||
$isTheme = $this->isTheme($input);
|
||||
$pluginName = $this->getPluginName($input, $output);
|
||||
$description = $this->getPluginDescription($input, $output);
|
||||
$version = $this->getPluginVersion($input, $output);
|
||||
|
||||
$this->generatePluginFolder($pluginName);
|
||||
|
||||
$plugin = new ExamplePlugin();
|
||||
$info = $plugin->getInformation();
|
||||
$exampleDescription = $info['description'];
|
||||
|
||||
if ($isTheme) {
|
||||
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExampleTheme';
|
||||
$replace = array(
|
||||
'ExampleTheme' => $pluginName,
|
||||
'ExampleDescription' => $description,
|
||||
'0.1.0' => $version
|
||||
$exampleDescription => $description,
|
||||
'0.1.0' => $version,
|
||||
'PIWIK_VERSION' => Version::VERSION
|
||||
);
|
||||
$whitelistFiles = array();
|
||||
|
||||
|
|
@ -55,47 +61,37 @@ class GeneratePlugin extends GeneratePluginBase
|
|||
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
|
||||
$replace = array(
|
||||
'ExamplePlugin' => $pluginName,
|
||||
'ExampleDescription' => $description,
|
||||
'0.1.0' => $version
|
||||
$exampleDescription => $description,
|
||||
'0.1.0' => $version,
|
||||
'PIWIK_VERSION' => Version::VERSION
|
||||
);
|
||||
$whitelistFiles = array(
|
||||
'/ExamplePlugin.php',
|
||||
'/plugin.json',
|
||||
'/README.md',
|
||||
'/.travis.yml',
|
||||
'/screenshots',
|
||||
'/screenshots/.gitkeep',
|
||||
'/javascripts',
|
||||
'/javascripts/plugin.js',
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
$this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles);
|
||||
|
||||
$this->writeSuccessMessage($output, array(
|
||||
sprintf('%s %s %s generated.', $isTheme ? 'Theme' : 'Plugin', $pluginName, $version),
|
||||
'Enjoy!'
|
||||
));
|
||||
|
||||
if ($createFullPlugin) {
|
||||
$this->executePluginCommand($output, 'generate:api', $pluginName);
|
||||
$this->executePluginCommand($output, 'generate:controller', $pluginName);
|
||||
if ($isTheme) {
|
||||
$this->writeSuccessMessage($output, array(
|
||||
sprintf('Theme %s %s generated.', $pluginName, $version),
|
||||
'If you have not done yet check out our Theming guide <comment>http://developer.piwik.org/guides/theming</comment>',
|
||||
'Enjoy!'
|
||||
));
|
||||
} else {
|
||||
$this->writeSuccessMessage($output, array(
|
||||
sprintf('Plugin %s %s generated.', $pluginName, $version),
|
||||
'Our developer guides will help you developing this plugin, check out <comment>http://developer.piwik.org/guides</comment>',
|
||||
'To see a list of available generators execute <comment>./console list generate</comment>',
|
||||
'Enjoy!'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private function executePluginCommand(OutputInterface $output, $commandName, $pluginName)
|
||||
{
|
||||
$command = $this->getApplication()->find($commandName);
|
||||
$arguments = array(
|
||||
'command' => $commandName,
|
||||
'--pluginname' => $pluginName
|
||||
);
|
||||
|
||||
$input = new ArrayInput($arguments);
|
||||
$command->run($input, $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @return bool
|
||||
|
|
@ -110,32 +106,40 @@ class GeneratePlugin extends GeneratePluginBase
|
|||
protected function generatePluginFolder($pluginName)
|
||||
{
|
||||
$pluginPath = $this->getPluginPath($pluginName);
|
||||
Filesystem::mkdir($pluginPath, true);
|
||||
Filesystem::mkdir($pluginPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
* @throws \RunTimeException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getPluginName(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$overwrite = $input->getOption('overwrite');
|
||||
|
||||
$self = $this;
|
||||
|
||||
$validate = function ($pluginName) use ($self) {
|
||||
$validate = function ($pluginName) use ($self, $overwrite) {
|
||||
if (empty($pluginName)) {
|
||||
throw new \RunTimeException('You have to enter a plugin name');
|
||||
throw new \RuntimeException('You have to enter a plugin name');
|
||||
}
|
||||
|
||||
if (!Filesystem::isValidFilename($pluginName)) {
|
||||
throw new \RunTimeException(sprintf('The plugin name %s is not valid', $pluginName));
|
||||
if(strlen($pluginName) > 40) {
|
||||
throw new \RuntimeException('Your plugin name cannot be longer than 40 characters');
|
||||
}
|
||||
|
||||
if (!Plugin\Manager::getInstance()->isValidPluginName($pluginName)) {
|
||||
throw new \RuntimeException(sprintf('The plugin name %s is not valid. The name must start with a letter and is only allowed to contain numbers and letters.', $pluginName));
|
||||
}
|
||||
|
||||
$pluginPath = $self->getPluginPath($pluginName);
|
||||
|
||||
if (file_exists($pluginPath)) {
|
||||
throw new \RunTimeException('A plugin with this name already exists');
|
||||
if (file_exists($pluginPath)
|
||||
&& !$overwrite
|
||||
) {
|
||||
throw new \RuntimeException('A plugin with this name already exists');
|
||||
}
|
||||
|
||||
return $pluginName;
|
||||
|
|
@ -159,16 +163,16 @@ class GeneratePlugin extends GeneratePluginBase
|
|||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return mixed
|
||||
* @throws \RunTimeException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getPluginDescription(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$validate = function ($description) {
|
||||
if (empty($description)) {
|
||||
throw new \RunTimeException('You have to enter a description');
|
||||
throw new \RuntimeException('You have to enter a description');
|
||||
}
|
||||
if (150 < strlen($description)) {
|
||||
throw new \RunTimeException('Description is too long, max 150 characters allowed.');
|
||||
throw new \RuntimeException('Description is too long, max 150 characters allowed.');
|
||||
}
|
||||
|
||||
return $description;
|
||||
|
|
@ -203,21 +207,4 @@ class GeneratePlugin extends GeneratePluginBase
|
|||
return $version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getCreateFullPlugin(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$full = $input->getOption('full');
|
||||
|
||||
if (is_null($full)) {
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
$full = $dialog->askConfirmation($output, 'Shall we also create an API and a Controller? (y/N)', false);
|
||||
}
|
||||
|
||||
return !empty($full);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -9,39 +9,232 @@
|
|||
|
||||
namespace Piwik\Plugins\CoreConsole\Commands;
|
||||
|
||||
|
||||
use Piwik\Development;
|
||||
use Piwik\Filesystem;
|
||||
use Piwik\Plugin\ConsoleCommand;
|
||||
use Piwik\Plugin\Dependency;
|
||||
use Piwik\Version;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
*/
|
||||
abstract class GeneratePluginBase extends ConsoleCommand
|
||||
{
|
||||
public function getPluginPath($pluginName)
|
||||
public function isEnabled()
|
||||
{
|
||||
return PIWIK_INCLUDE_PATH . '/plugins/' . ucfirst($pluginName);
|
||||
return Development::isEnabled();
|
||||
}
|
||||
|
||||
private function createFolderWithinPluginIfNotExists($pluginName, $folder)
|
||||
public function getPluginPath($pluginName)
|
||||
{
|
||||
$pluginPath = $this->getPluginPath($pluginName);
|
||||
return PIWIK_INCLUDE_PATH . $this->getRelativePluginPath($pluginName);
|
||||
}
|
||||
|
||||
if (!file_exists($pluginName . $folder)) {
|
||||
Filesystem::mkdir($pluginPath . $folder, true);
|
||||
private function getRelativePluginPath($pluginName)
|
||||
{
|
||||
return '/plugins/' . $pluginName;
|
||||
}
|
||||
|
||||
private function createFolderWithinPluginIfNotExists($pluginNameOrCore, $folder)
|
||||
{
|
||||
if ($pluginNameOrCore === 'core') {
|
||||
$pluginPath = $this->getPathToCore();
|
||||
} else {
|
||||
$pluginPath = $this->getPluginPath($pluginNameOrCore);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
protected function checkAndUpdateRequiredPiwikVersion($pluginName, OutputInterface $output)
|
||||
{
|
||||
$pluginJsonPath = $this->getPluginPath($pluginName) . '/plugin.json';
|
||||
$relativePluginJson = $this->getRelativePluginPath($pluginName) . '/plugin.json';
|
||||
|
||||
if (!file_exists($pluginJsonPath) || !is_writable($pluginJsonPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$pluginJson = file_get_contents($pluginJsonPath);
|
||||
$pluginJson = json_decode($pluginJson, true);
|
||||
|
||||
if (empty($pluginJson)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($pluginJson['require'])) {
|
||||
$pluginJson['require'] = array();
|
||||
}
|
||||
|
||||
$piwikVersion = Version::VERSION;
|
||||
$newRequiredVersion = '>=' . $piwikVersion;
|
||||
|
||||
if (!empty($pluginJson['require']['piwik'])) {
|
||||
$requiredVersion = $pluginJson['require']['piwik'];
|
||||
|
||||
if ($requiredVersion === $newRequiredVersion) {
|
||||
return;
|
||||
}
|
||||
|
||||
$dependency = new Dependency();
|
||||
$missingVersion = $dependency->getMissingVersions($piwikVersion, $requiredVersion);
|
||||
|
||||
if (!empty($missingVersion)) {
|
||||
$msg = sprintf('We cannot generate this component as the plugin "%s" requires the Piwik version "%s" in the file "%s". Generating this component requires "%s". If you know your plugin is compatible with your Piwik version remove the required Piwik version in "%s" and try to execute this command again.', $pluginName, $requiredVersion, $relativePluginJson, $newRequiredVersion, $relativePluginJson);
|
||||
|
||||
throw new \Exception($msg);
|
||||
}
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln(sprintf('<comment>We have updated the required Piwik version from "%s" to "%s" in "%s".</comment>', $requiredVersion, $newRequiredVersion, $relativePluginJson));
|
||||
} else {
|
||||
$output->writeln('');
|
||||
$output->writeln(sprintf('<comment>We have updated your "%s" to require the Piwik version "%s".</comment>', $relativePluginJson, $newRequiredVersion));
|
||||
}
|
||||
|
||||
$pluginJson['require']['piwik'] = $newRequiredVersion;
|
||||
file_put_contents($pluginJsonPath, $this->toJson($pluginJson));
|
||||
}
|
||||
|
||||
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
|
||||
|
|
@ -67,16 +260,13 @@ abstract class GeneratePluginBase extends ConsoleCommand
|
|||
}
|
||||
|
||||
if (is_dir($file)) {
|
||||
$fileNamePlugin = $this->replaceContent($replace, $fileNamePlugin);
|
||||
$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);
|
||||
}
|
||||
|
|
@ -114,7 +304,7 @@ abstract class GeneratePluginBase extends ConsoleCommand
|
|||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
* @throws \RunTimeException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function askPluginNameAndValidate(InputInterface $input, OutputInterface $output, $pluginNames, $invalidArgumentException)
|
||||
{
|
||||
|
|
@ -135,9 +325,22 @@ abstract class GeneratePluginBase extends ConsoleCommand
|
|||
$validate($pluginName);
|
||||
}
|
||||
|
||||
$pluginName = ucfirst($pluginName);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
300
www/analytics/plugins/CoreConsole/Commands/GenerateReport.php
Normal file
300
www/analytics/plugins/CoreConsole/Commands/GenerateReport.php
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
<?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\Columns\Dimension;
|
||||
use Piwik\Plugin\Manager;
|
||||
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;
|
||||
|
||||
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);
|
||||
$this->checkAndUpdateRequiredPiwikVersion($pluginName, $output);
|
||||
|
||||
$reportName = $this->getReportName($input, $output);
|
||||
$category = $this->getCategory($input, $output, $pluginName);
|
||||
$documentation = $this->getDocumentation($input, $output);
|
||||
list($dimension, $dimensionClass) = $this->getDimension($input, $output, $pluginName);
|
||||
|
||||
$order = $this->getOrder($category);
|
||||
$apiName = $this->getApiName($reportName);
|
||||
|
||||
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExampleReport';
|
||||
$replace = array('GetExampleReport' => ucfirst($apiName),
|
||||
'getExampleReport' => lcfirst($apiName),
|
||||
'getApiReport' => lcfirst($apiName),
|
||||
'ExampleCategory' => $category,
|
||||
'ExampleReportName' => $this->makeTranslationIfPossible($pluginName, $reportName),
|
||||
'ExampleReportDocumentation' => $documentation,
|
||||
'999' => $order,
|
||||
'new ExitPageUrl()' => $dimension,
|
||||
'use Piwik\Plugins\Actions\Columns\ExitPageUrl;' => $dimensionClass,
|
||||
'ExampleReport' => $pluginName,
|
||||
);
|
||||
|
||||
$whitelistFiles = array('/Reports', '/Reports/Base.php', '/Reports/GetExampleReport.php');
|
||||
|
||||
if (file_exists($this->getPluginPath($pluginName) . '/API.php')) {
|
||||
$this->copyTemplateMethodToExisitingClass('Piwik\Plugins\ExampleReport\API', 'getExampleReport', $replace);
|
||||
} else {
|
||||
$whitelistFiles[] = '/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 $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
|
||||
* @param string $pluginName
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getDimension(InputInterface $input, OutputInterface $output, $pluginName)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$plugin = Manager::getInstance()->loadPlugin($pluginName);
|
||||
$dimensions = Dimension::getAllDimensions();
|
||||
$dimensions = array_merge($dimensions, Dimension::getDimensions($plugin));
|
||||
|
||||
foreach ($dimensions as $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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?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 Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
*/
|
||||
class GenerateScheduledTask extends GeneratePluginBase
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('generate:scheduledtask')
|
||||
->setDescription('Adds a tasks class to an existing plugin which allows you to specify scheduled tasks')
|
||||
->addOption('pluginname', null, InputOption::VALUE_REQUIRED, 'The name of an existing plugin which does not have any tasks defined yet');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginName = $this->getPluginName($input, $output);
|
||||
$this->checkAndUpdateRequiredPiwikVersion($pluginName, $output);
|
||||
|
||||
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
|
||||
$replace = array('ExamplePlugin' => $pluginName);
|
||||
$whitelistFiles = array('/Tasks.php');
|
||||
|
||||
$this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles);
|
||||
|
||||
$this->writeSuccessMessage($output, array(
|
||||
sprintf('Tasks.php for %s generated.', $pluginName),
|
||||
'You can now start specifying your scheduled tasks',
|
||||
'Enjoy!'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getPluginName(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginNames = $this->getPluginNamesHavingNotSpecificFile('Tasks.php');
|
||||
$invalidName = 'You have to enter the name of an existing plugin which does not already have any tasks defined';
|
||||
|
||||
return $this->askPluginNameAndValidate($input, $output, $pluginNames, $invalidName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -27,6 +27,7 @@ class GenerateSettings extends GeneratePluginBase
|
|||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginName = $this->getPluginName($input, $output);
|
||||
$this->checkAndUpdateRequiredPiwikVersion($pluginName, $output);
|
||||
|
||||
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExampleSettingsPlugin';
|
||||
$replace = array('ExampleSettingsPlugin' => $pluginName);
|
||||
|
|
@ -45,7 +46,7 @@ class GenerateSettings extends GeneratePluginBase
|
|||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
* @throws \RunTimeException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getPluginName(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -24,54 +24,53 @@ class GenerateTest extends GeneratePluginBase
|
|||
->setDescription('Adds a test to an existing plugin')
|
||||
->addOption('pluginname', null, InputOption::VALUE_REQUIRED, 'The name of an existing plugin')
|
||||
->addOption('testname', null, InputOption::VALUE_REQUIRED, 'The name of the test to create')
|
||||
->addOption('testtype', null, InputOption::VALUE_REQUIRED, 'Whether you want to create a "unit", "integration" or "database" test');
|
||||
->addOption('testtype', null, InputOption::VALUE_REQUIRED, 'Whether you want to create a "unit", "integration", "system", or "ui" test');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginName = $this->getPluginName($input, $output);
|
||||
$testName = $this->getTestName($input, $output);
|
||||
$testType = $this->getTestType($input, $output);
|
||||
$testName = $this->getTestName($input, $output, $testType);
|
||||
|
||||
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
|
||||
$replace = array(
|
||||
'ExamplePlugin' => $pluginName,
|
||||
'SimpleTest' => $testName,
|
||||
'SimpleIntegrationTest' => $testName,
|
||||
'@group Plugins' => '@group ' . $testType
|
||||
'ExamplePlugin' => $pluginName,
|
||||
'SimpleTest' => $testName,
|
||||
'SimpleSystemTest' => $testName,
|
||||
'SimpleUITest_spec.js' => $testName . '_spec.js',
|
||||
'SimpleUITest' => $testName,
|
||||
);
|
||||
|
||||
$testClass = $this->getTestClass($testType);
|
||||
if(!empty($testClass)) {
|
||||
$replace['\PHPUnit_Framework_TestCase'] = $testClass;
|
||||
|
||||
}
|
||||
|
||||
$whitelistFiles = $this->getTestFilesWhitelist($testType);
|
||||
$this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles);
|
||||
|
||||
$this->writeSuccessMessage($output, array(
|
||||
sprintf('Test %s for plugin %s generated.', $testName, $pluginName),
|
||||
'You can now start writing beautiful tests!',
|
||||
$messages = array(
|
||||
sprintf('Test %s for plugin %s generated.', $testName, $pluginName),
|
||||
);
|
||||
|
||||
));
|
||||
if (strtolower($testType) === 'ui') {
|
||||
$messages[] = 'To run this test execute the command: ';
|
||||
$messages[] = '<comment>' . sprintf('./console tests:run-ui %s', $testName) . '</comment>';
|
||||
} else {
|
||||
$messages[] = 'To run all your plugin tests, execute the command: ';
|
||||
$messages[] = '<comment>' . sprintf('./console tests:run %s', $pluginName) . '</comment>';
|
||||
$messages[] = 'To run only this test: ';
|
||||
$messages[] = '<comment>' . sprintf('./console tests:run %s', $testName) . '</comment>';
|
||||
}
|
||||
|
||||
$this->writeSuccessMessage($output, array(
|
||||
'To run all your plugin tests, execute the command: ',
|
||||
sprintf('./console tests:run %s', $pluginName),
|
||||
'To run only this test: ',
|
||||
sprintf('./console tests:run %s', $testName),
|
||||
'Enjoy!'
|
||||
));
|
||||
$messages[] = 'Enjoy!';
|
||||
|
||||
$this->writeSuccessMessage($output, $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return string
|
||||
* @throws \RunTimeException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function getTestName(InputInterface $input, OutputInterface $output)
|
||||
private function getTestName(InputInterface $input, OutputInterface $output, $testType)
|
||||
{
|
||||
$testname = $input->getOption('testname');
|
||||
|
||||
|
|
@ -90,7 +89,7 @@ class GenerateTest extends GeneratePluginBase
|
|||
$validate($testname);
|
||||
}
|
||||
|
||||
if (!Common::stringEndsWith(strtolower($testname), 'test')) {
|
||||
if (strtolower($testType) !== 'ui' && !Common::stringEndsWith(strtolower($testname), 'test')) {
|
||||
$testname = $testname . 'Test';
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +102,7 @@ class GenerateTest extends GeneratePluginBase
|
|||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
* @throws \RunTimeException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getPluginName(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
|
@ -113,30 +112,15 @@ class GenerateTest extends GeneratePluginBase
|
|||
return $this->askPluginNameAndValidate($input, $output, $pluginNames, $invalidName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @return string
|
||||
*/
|
||||
private function getTestClass($testType)
|
||||
{
|
||||
if ('Database' == $testType) {
|
||||
return '\DatabaseTestCase';
|
||||
}
|
||||
if ('Unit' == $testType) {
|
||||
return '\PHPUnit_Framework_TestCase';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getValidTypes()
|
||||
{
|
||||
return array('unit', 'integration', 'database');
|
||||
return array('unit', 'integration', 'system', 'ui');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return string Unit, Integration, Database
|
||||
* @return string Unit, Integration, System
|
||||
*/
|
||||
private function getTestType(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
|
@ -167,23 +151,46 @@ class GenerateTest extends GeneratePluginBase
|
|||
*/
|
||||
protected function getTestFilesWhitelist($testType)
|
||||
{
|
||||
if('Integration' == $testType) {
|
||||
if ('Ui' == $testType) {
|
||||
return array(
|
||||
'/tests',
|
||||
'/tests/UI',
|
||||
'/tests/UI/.gitignore',
|
||||
'/tests/UI/expected-ui-screenshots',
|
||||
'/tests/UI/expected-ui-screenshots/.gitkeep',
|
||||
'/tests/UI/SimpleUITest_spec.js',
|
||||
);
|
||||
}
|
||||
|
||||
if ('System' == $testType) {
|
||||
return array(
|
||||
'/.gitignore',
|
||||
'/tests',
|
||||
'/tests/SimpleIntegrationTest.php',
|
||||
'/tests/expected',
|
||||
'/tests/expected/test___API.get_day.xml',
|
||||
'/tests/expected/test___Goals.getItemsSku_day.xml',
|
||||
'/tests/processed',
|
||||
'/tests/processed/.gitignore',
|
||||
'/tests/fixtures',
|
||||
'/tests/fixtures/SimpleFixtureTrackFewVisits.php'
|
||||
'/tests/System',
|
||||
'/tests/System/SimpleSystemTest.php',
|
||||
'/tests/System/expected',
|
||||
'/tests/System/expected/test___API.get_day.xml',
|
||||
'/tests/System/expected/test___Goals.getItemsSku_day.xml',
|
||||
'/tests/System/processed',
|
||||
'/tests/System/processed/.gitignore',
|
||||
'/tests/Fixtures',
|
||||
'/tests/Fixtures/SimpleFixtureTrackFewVisits.php'
|
||||
);
|
||||
}
|
||||
|
||||
if ('Integration' == $testType) {
|
||||
|
||||
return array(
|
||||
'/tests',
|
||||
'/tests/Integration',
|
||||
'/tests/Integration/SimpleTest.php'
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'/tests',
|
||||
'/tests/SimpleTest.php'
|
||||
'/tests/Unit',
|
||||
'/tests/Unit/SimpleTest.php'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
122
www/analytics/plugins/CoreConsole/Commands/GenerateUpdate.php
Normal file
122
www/analytics/plugins/CoreConsole/Commands/GenerateUpdate.php
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
<?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\Updates' => $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, '\\');
|
||||
|
||||
if ($component !== 'core') {
|
||||
$className .= '\Updates';
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
namespace Piwik\Plugins\CoreConsole\Commands;
|
||||
|
||||
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
|
@ -33,6 +31,7 @@ class GenerateVisualizationPlugin extends GeneratePlugin
|
|||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginName = $this->getPluginName($input, $output);
|
||||
$this->checkAndUpdateRequiredPiwikVersion($pluginName, $output);
|
||||
$description = $this->getPluginDescription($input, $output);
|
||||
$version = $this->getPluginVersion($input, $output);
|
||||
$visualizationName = $this->getVisualizationName($input, $output);
|
||||
|
|
@ -43,7 +42,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
|
||||
);
|
||||
|
|
@ -60,7 +59,7 @@ class GenerateVisualizationPlugin extends GeneratePlugin
|
|||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return string
|
||||
* @throws \RunTimeException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function getVisualizationName(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
|
@ -68,11 +67,11 @@ class GenerateVisualizationPlugin extends GeneratePlugin
|
|||
|
||||
$validate = function ($visualizationName) use ($self) {
|
||||
if (empty($visualizationName)) {
|
||||
throw new \RunTimeException('You have to enter a visualization name');
|
||||
throw new \RuntimeException('You have to enter a visualization name');
|
||||
}
|
||||
|
||||
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 +81,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);
|
||||
}
|
||||
|
|
@ -92,5 +91,4 @@ class GenerateVisualizationPlugin extends GeneratePlugin
|
|||
return $visualizationName;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
120
www/analytics/plugins/CoreConsole/Commands/GenerateWidget.php
Normal file
120
www/analytics/plugins/CoreConsole/Commands/GenerateWidget.php
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
<?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\Piwik;
|
||||
use Piwik\Plugin\Widgets;
|
||||
use Piwik\Translate;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
*/
|
||||
class GenerateWidget extends GeneratePluginBase
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('generate:widget')
|
||||
->setDescription('Adds a plugin widget class to an existing plugin')
|
||||
->addOption('pluginname', null, InputOption::VALUE_REQUIRED, 'The name of an existing plugin which does not have any widgets defined yet')
|
||||
->addOption('category', null, InputOption::VALUE_REQUIRED, 'The name of the category the widget should belong to');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginName = $this->getPluginName($input, $output);
|
||||
$this->checkAndUpdateRequiredPiwikVersion($pluginName, $output);
|
||||
|
||||
$category = $this->getCategory($input, $output);
|
||||
|
||||
if ($category === Piwik::translate($category)) {
|
||||
// no translation found...
|
||||
$category = $this->makeTranslationIfPossible($pluginName, $category);
|
||||
}
|
||||
|
||||
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
|
||||
$replace = array('ExamplePlugin' => $pluginName,
|
||||
'Example Category' => $category);
|
||||
$whitelistFiles = array('/Widgets.php');
|
||||
|
||||
$this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles);
|
||||
|
||||
$this->writeSuccessMessage($output, array(
|
||||
sprintf('Widgets.php for %s generated.', $pluginName),
|
||||
'You can now start defining your plugin widgets',
|
||||
'Enjoy!'
|
||||
));
|
||||
}
|
||||
|
||||
protected function getExistingCategories()
|
||||
{
|
||||
$categories = array();
|
||||
foreach (Widgets::getAllWidgets() as $widget) {
|
||||
if ($widget->getCategory()) {
|
||||
$categories[] = Piwik::translate($widget->getCategory());
|
||||
}
|
||||
}
|
||||
$categories = array_values(array_unique($categories));
|
||||
|
||||
return $categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function getCategory(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$validate = function ($category) {
|
||||
if (empty($category)) {
|
||||
throw new \InvalidArgumentException('Please enter the name of the category your widget should belong to');
|
||||
}
|
||||
|
||||
return $category;
|
||||
};
|
||||
|
||||
$category = $input->getOption('category');
|
||||
$categories = $this->getExistingCategories();
|
||||
|
||||
if (empty($category)) {
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
$category = $dialog->askAndValidate($output, 'Enter the widget 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 getPluginName(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$pluginNames = $this->getPluginNamesHavingNotSpecificFile('Widgets.php');
|
||||
$invalidName = 'You have to enter the name of an existing plugin which does not already have any widgets defined';
|
||||
|
||||
return $this->askPluginNameAndValidate($input, $output, $pluginNames, $invalidName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -9,8 +9,9 @@
|
|||
|
||||
namespace Piwik\Plugins\CoreConsole\Commands;
|
||||
|
||||
use Piwik\Development;
|
||||
use Piwik\Plugin\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Piwik\SettingsPiwik;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
|
@ -19,6 +20,11 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||
*/
|
||||
class GitCommit extends ConsoleCommand
|
||||
{
|
||||
public function isEnabled()
|
||||
{
|
||||
return Development::isEnabled() && SettingsPiwik::isGitDeployment();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('git:commit')
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -10,15 +10,19 @@
|
|||
namespace Piwik\Plugins\CoreConsole\Commands;
|
||||
|
||||
use Piwik\Plugin\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Piwik\SettingsPiwik;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
*/
|
||||
class GitPull extends ConsoleCommand
|
||||
{
|
||||
public function isEnabled()
|
||||
{
|
||||
return SettingsPiwik::isGitDeployment();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('git:pull');
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -9,16 +9,21 @@
|
|||
|
||||
namespace Piwik\Plugins\CoreConsole\Commands;
|
||||
|
||||
use Piwik\Development;
|
||||
use Piwik\Plugin\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Piwik\SettingsPiwik;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
*/
|
||||
class GitPush extends ConsoleCommand
|
||||
{
|
||||
public function isEnabled()
|
||||
{
|
||||
return Development::isEnabled() && SettingsPiwik::isGitDeployment();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('git:push');
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -8,8 +8,11 @@
|
|||
|
||||
namespace Piwik\Plugins\CoreConsole\Commands;
|
||||
|
||||
use Piwik\Plugin\Manager;
|
||||
use Piwik\Plugin\ConsoleCommand;
|
||||
use Piwik\Plugins\CorePluginsAdmin\Commands\ActivatePlugin;
|
||||
use Piwik\Plugins\CorePluginsAdmin\Commands\DeactivatePlugin;
|
||||
use Piwik\Plugins\CorePluginsAdmin\Commands\ListPlugins;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
|
@ -17,6 +20,8 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||
|
||||
/**
|
||||
* core:plugin console command.
|
||||
*
|
||||
* @deprecated This command has been replaced with `plugin:*` commands.
|
||||
*/
|
||||
class ManagePlugin extends ConsoleCommand
|
||||
{
|
||||
|
|
@ -26,16 +31,17 @@ class ManagePlugin extends ConsoleCommand
|
|||
{
|
||||
$this->setName('core:plugin');
|
||||
$this->setDescription("Perform various actions regarding one or more plugins.");
|
||||
$this->addArgument("operation", InputArgument::REQUIRED, "Operation to apply (can be 'activate' or 'deactivate').");
|
||||
$this->addArgument("plugins", InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'Plugin name(s) to activate.');
|
||||
$this->addArgument("operation", InputArgument::REQUIRED, "Operation to apply (can be 'activate' or 'deactivate' or 'list').");
|
||||
$this->addArgument("plugins", InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Plugin name(s) to activate.');
|
||||
$this->addOption('domain', null, InputOption::VALUE_REQUIRED, "The domain to activate the plugin for.");
|
||||
|
||||
$this->operations['activate'] = 'activatePlugin';
|
||||
$this->operations['deactivate'] = 'deactivatePlugin';
|
||||
$this->operations['list'] = 'listPlugins';
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute command like: ./console cloudadmin:plugin activate CustomAlerts --piwik-domain=testcustomer.piwik.pro
|
||||
* Execute command like: ./console core:plugin activate CustomAlerts --piwik-domain=testcustomer.piwik.pro
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
|
@ -43,10 +49,27 @@ class ManagePlugin extends ConsoleCommand
|
|||
$plugins = $input->getArgument('plugins');
|
||||
|
||||
if (empty($this->operations[$operation])) {
|
||||
throw new Exception("Invalid operation '$operation'.");
|
||||
throw new \Exception("Invalid operation '$operation'.");
|
||||
}
|
||||
|
||||
$fn = $this->operations[$operation];
|
||||
|
||||
|
||||
if($fn == 'listPlugins') {
|
||||
call_user_func(array($this, $fn), $input, $output);
|
||||
} else {
|
||||
$this->applyOperationToEachPlugin($input, $output, $plugins, $fn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @param $plugins
|
||||
* @param $fn
|
||||
*/
|
||||
protected function applyOperationToEachPlugin(InputInterface $input, OutputInterface $output, $plugins, $fn)
|
||||
{
|
||||
foreach ($plugins as $plugin) {
|
||||
call_user_func(array($this, $fn), $input, $output, $plugin);
|
||||
}
|
||||
|
|
@ -54,15 +77,32 @@ class ManagePlugin extends ConsoleCommand
|
|||
|
||||
private function activatePlugin(InputInterface $input, OutputInterface $output, $plugin)
|
||||
{
|
||||
Manager::getInstance()->activatePlugin($plugin, $input, $output);
|
||||
$output->writeln('<comment>Warning: the command core:plugin is deprecated, use plugin:activate instead.</comment>');
|
||||
|
||||
$output->writeln("Activated plugin <info>$plugin</info>");
|
||||
$command = new ActivatePlugin();
|
||||
$input = new ArrayInput(array(
|
||||
'plugin' => $plugin,
|
||||
));
|
||||
return $command->run($input, $output);
|
||||
}
|
||||
|
||||
private function deactivatePlugin(InputInterface $input, OutputInterface $output, $plugin)
|
||||
{
|
||||
Manager::getInstance()->deactivatePlugin($plugin, $input, $output);
|
||||
$output->writeln('<comment>Warning: the command core:plugin is deprecated, use plugin:deactivate instead.</comment>');
|
||||
|
||||
$output->writeln("Deactivated plugin <info>$plugin</info>");
|
||||
$command = new DeactivatePlugin();
|
||||
$input = new ArrayInput(array(
|
||||
'plugin' => $plugin,
|
||||
));
|
||||
return $command->run($input, $output);
|
||||
}
|
||||
|
||||
private function listPlugins(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output->writeln('<comment>Warning: the command core:plugin is deprecated, use plugin:list instead.</comment>');
|
||||
|
||||
$command = new ListPlugins();
|
||||
$input = new ArrayInput(array());
|
||||
return $command->run($input, $output);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @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\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
*/
|
||||
class RunTests extends ConsoleCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('tests:run');
|
||||
$this->setDescription('Run Piwik PHPUnit tests one group after the other');
|
||||
$this->addArgument('group', InputArgument::OPTIONAL, 'Run only a specific test group. Separate multiple groups by comma, for instance core,integration', '');
|
||||
$this->addOption('options', 'o', InputOption::VALUE_OPTIONAL, 'All options will be forwarded to phpunit', '');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$options = $input->getOption('options');
|
||||
$groups = $input->getArgument('group');
|
||||
|
||||
$groups = explode(",", $groups);
|
||||
$groups = array_map('ucfirst', $groups);
|
||||
$groups = array_filter($groups, 'strlen');
|
||||
|
||||
$command = 'phpunit';
|
||||
|
||||
// force xdebug usage for coverage options
|
||||
if (false !== strpos($options, '--coverage') && !extension_loaded('xdebug')) {
|
||||
|
||||
$output->writeln('<info>xdebug extension required for code coverage.</info>');
|
||||
|
||||
$output->writeln('<info>searching for xdebug extension...</info>');
|
||||
|
||||
$extensionDir = shell_exec('php-config --extension-dir');
|
||||
$xdebugFile = trim($extensionDir) . DIRECTORY_SEPARATOR . 'xdebug.so';
|
||||
|
||||
if (!file_exists($xdebugFile)) {
|
||||
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
|
||||
$xdebugFile = $dialog->askAndValidate($output, 'xdebug not found. Please provide path to xdebug.so', function($xdebugFile) {
|
||||
return file_exists($xdebugFile);
|
||||
});
|
||||
} else {
|
||||
|
||||
$output->writeln('<info>xdebug extension found in extension path.</info>');
|
||||
}
|
||||
|
||||
$output->writeln("<info>using $xdebugFile as xdebug extension.</info>");
|
||||
|
||||
$phpunitPath = trim(shell_exec('which phpunit'));
|
||||
|
||||
$command = sprintf('php -d zend_extension=%s %s', $xdebugFile, $phpunitPath);
|
||||
}
|
||||
|
||||
if(empty($groups)) {
|
||||
$groups = $this->getTestsGroups();
|
||||
}
|
||||
foreach($groups as $group) {
|
||||
$params = '--group ' . $group . ' ' . str_replace('%group%', $group, $options);
|
||||
$cmd = sprintf('cd %s/tests/PHPUnit && %s %s', PIWIK_DOCUMENT_ROOT, $command, $params);
|
||||
$output->writeln('Executing command: <info>' . $cmd . '</info>');
|
||||
passthru($cmd);
|
||||
$output->writeln("");
|
||||
}
|
||||
}
|
||||
|
||||
private function getTestsGroups()
|
||||
{
|
||||
return array('Core', 'Plugins', 'Integration', 'UI');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @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\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class RunUITests extends ConsoleCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('tests:run-ui');
|
||||
$this->setDescription('Run screenshot tests');
|
||||
$this->addArgument('specs', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Run only a specific test spec. Separate multiple specs by comma, for instance core,integration', array());
|
||||
$this->addOption("persist-fixture-data", null, InputOption::VALUE_NONE, "Persist test data in a database and do not execute tear down.");
|
||||
$this->addOption('keep-symlinks', null, InputOption::VALUE_NONE, "Keep recursive directory symlinks so test pages can be viewed in a browser.");
|
||||
$this->addOption('print-logs', null, InputOption::VALUE_NONE, "Print webpage logs even if tests succeed.");
|
||||
$this->addOption('drop', null, InputOption::VALUE_NONE, "Drop the existing database and re-setup a persisted fixture.");
|
||||
$this->addOption('plugin', null, InputOption::VALUE_REQUIRED, "Execute all tests for a plugin.");
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$specs = $input->getArgument('specs');
|
||||
$persistFixtureData = $input->getOption("persist-fixture-data");
|
||||
$keepSymlinks = $input->getOption('keep-symlinks');
|
||||
$printLogs = $input->getOption('print-logs');
|
||||
$drop = $input->getOption('drop');
|
||||
$plugin = $input->getOption('plugin');
|
||||
|
||||
$options = array();
|
||||
if ($persistFixtureData) {
|
||||
$options[] = "--persist-fixture-data";
|
||||
}
|
||||
|
||||
if ($keepSymlinks) {
|
||||
$options[] = "--keep-symlinks";
|
||||
}
|
||||
|
||||
if ($printLogs) {
|
||||
$options[] = "--print-logs";
|
||||
}
|
||||
|
||||
if ($drop) {
|
||||
$options[] = "--drop";
|
||||
}
|
||||
|
||||
if ($plugin) {
|
||||
$options[] = "--plugin=" . $plugin;
|
||||
}
|
||||
$options = implode(" ", $options);
|
||||
|
||||
$specs = implode(" ", $specs);
|
||||
|
||||
$cmd = "phantomjs '" . PIWIK_INCLUDE_PATH . "/tests/lib/screenshot-testing/run-tests.js' $options $specs";
|
||||
|
||||
$output->writeln('Executing command: <info>' . $cmd . '</info>');
|
||||
$output->writeln('');
|
||||
|
||||
passthru($cmd);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @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\Url;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Config;
|
||||
use Piwik\Plugin\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Console commands that sets up a fixture either in a local MySQL database or a remote one.
|
||||
*
|
||||
* TODO: use this console command in UI tests instead of setUpDatabase.php/tearDownDatabase.php scripts
|
||||
*/
|
||||
class SetupFixture extends ConsoleCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('tests:setup-fixture');
|
||||
$this->setDescription('Create a database and fill it with data using a Piwik test fixture.');
|
||||
|
||||
$this->addArgument('fixture', InputArgument::REQUIRED,
|
||||
"The class name of the fixture to apply. Doesn't need to have a namespace if it exists in the " .
|
||||
"Piwik\\Tests\\Fixtures namespace.");
|
||||
|
||||
$this->addOption('db-name', null, InputOption::VALUE_REQUIRED,
|
||||
"The name of the database that will contain the fixture data. This option is required to be set.");
|
||||
$this->addOption('file', null, InputOption::VALUE_REQUIRED,
|
||||
"The file location of the fixture. If this option is included the file will be required explicitly.");
|
||||
$this->addOption('db-host', null, InputOption::VALUE_REQUIRED,
|
||||
"The hostname of the MySQL database to use. Uses the default config value if not specified.");
|
||||
$this->addOption('db-user', null, InputOption::VALUE_REQUIRED,
|
||||
"The name of the MySQL user to use. Uses the default config value if not specified.");
|
||||
$this->addOption('db-pass', null, InputOption::VALUE_REQUIRED,
|
||||
"The MySQL user password to use. Uses the default config value if not specified.");
|
||||
$this->addOption('teardown', null, InputOption::VALUE_NONE,
|
||||
"If specified, the fixture will be torn down and the database deleted. Won't work if the --db-name " .
|
||||
"option isn't supplied.");
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$dbName = $input->getOption('db-name');
|
||||
if (!$dbName) {
|
||||
throw new \Exception("Required argument --db-name is not set.");
|
||||
}
|
||||
|
||||
$this->requireFixtureFiles();
|
||||
$this->setIncludePathAsInTestBootstrap();
|
||||
|
||||
$file = $input->getOption('file');
|
||||
if ($file) {
|
||||
if (is_file($file)) {
|
||||
require_once $file;
|
||||
} else if (is_file(PIWIK_INCLUDE_PATH . '/' . $file)) {
|
||||
require_once PIWIK_INCLUDE_PATH . '/' . $file;
|
||||
} else {
|
||||
throw new \Exception("Cannot find --file option file '$file'.");
|
||||
}
|
||||
}
|
||||
|
||||
$host = Url::getHost();
|
||||
if (empty($host)) {
|
||||
Url::setHost('localhost');
|
||||
}
|
||||
|
||||
// get the fixture class
|
||||
$fixtureClass = $input->getArgument('fixture');
|
||||
if (class_exists("Piwik\\Tests\\Fixtures\\" . $fixtureClass)) {
|
||||
$fixtureClass = "Piwik\\Tests\\Fixtures\\" . $fixtureClass;
|
||||
}
|
||||
|
||||
if (!class_exists($fixtureClass)) {
|
||||
throw new \Exception("Cannot find fixture class '$fixtureClass'.");
|
||||
}
|
||||
|
||||
// create the fixture
|
||||
$fixture = new $fixtureClass();
|
||||
$fixture->dbName = $dbName;
|
||||
$fixture->printToScreen = true;
|
||||
|
||||
Config::getInstance()->setTestEnvironment();
|
||||
$fixture->createConfig = false;
|
||||
|
||||
// setup database overrides
|
||||
$testingEnvironment = $fixture->getTestEnvironment();
|
||||
|
||||
$optionsToOverride = array(
|
||||
'dbname' => $dbName,
|
||||
'host' => $input->getOption('db-host'),
|
||||
'user' => $input->getOption('db-user'),
|
||||
'password' => $input->getOption('db-pass')
|
||||
);
|
||||
foreach ($optionsToOverride as $configOption => $value) {
|
||||
if ($value) {
|
||||
$configOverride = $testingEnvironment->configOverride;
|
||||
$configOverride['database_tests'][$configOption] = $configOverride['database'][$configOption] = $value;
|
||||
$testingEnvironment->configOverride = $configOverride;
|
||||
|
||||
Config::getInstance()->database[$configOption] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
// perform setup and/or teardown
|
||||
if ($input->getOption('teardown')) {
|
||||
$testingEnvironment->save();
|
||||
$fixture->performTearDown();
|
||||
} else {
|
||||
$fixture->performSetUp();
|
||||
}
|
||||
|
||||
$this->writeSuccessMessage($output, array("Fixture successfully setup!"));
|
||||
}
|
||||
|
||||
private function requireFixtureFiles()
|
||||
{
|
||||
require_once "PHPUnit/Autoload.php";
|
||||
|
||||
require_once PIWIK_INCLUDE_PATH . '/libs/PiwikTracker/PiwikTracker.php';
|
||||
require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/FakeAccess.php';
|
||||
require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/TestingEnvironment.php';
|
||||
require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/Fixture.php';
|
||||
|
||||
$fixturesToLoad = array(
|
||||
'/tests/PHPUnit/Fixtures/*.php',
|
||||
'/tests/PHPUnit/UI/Fixtures/*.php',
|
||||
);
|
||||
foreach($fixturesToLoad as $fixturePath) {
|
||||
foreach (glob(PIWIK_INCLUDE_PATH . $fixturePath) as $file) {
|
||||
require_once $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function setIncludePathAsInTestBootstrap()
|
||||
{
|
||||
if (!defined('PIWIK_INCLUDE_SEARCH_PATH')) {
|
||||
define('PIWIK_INCLUDE_SEARCH_PATH', get_include_path()
|
||||
. PATH_SEPARATOR . PIWIK_INCLUDE_PATH . '/core'
|
||||
. PATH_SEPARATOR . PIWIK_INCLUDE_PATH . '/libs'
|
||||
. PATH_SEPARATOR . PIWIK_INCLUDE_PATH . '/plugins');
|
||||
}
|
||||
@ini_set('include_path', PIWIK_INCLUDE_SEARCH_PATH);
|
||||
@set_include_path(PIWIK_INCLUDE_SEARCH_PATH);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @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\Http;
|
||||
use Piwik\Plugin\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
*/
|
||||
class SyncUITestScreenshots extends ConsoleCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('development:sync-ui-test-screenshots');
|
||||
$this->setDescription('For Piwik core devs. Copies screenshots '
|
||||
. 'from travis artifacts to tests/PHPUnit/UI/expected-ui-screenshots/');
|
||||
$this->addArgument('buildnumber', InputArgument::REQUIRED, 'Travis build number you want to sync.');
|
||||
$this->addArgument('screenshotsRegex', InputArgument::OPTIONAL,
|
||||
'A regex to use when selecting screenshots to copy. If not supplied all screenshots are copied.', '.*');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$buildNumber = $input->getArgument('buildnumber');
|
||||
$screenshotsRegex = $input->getArgument('screenshotsRegex');
|
||||
|
||||
if (empty($buildNumber)) {
|
||||
throw new \InvalidArgumentException('Missing build number.');
|
||||
}
|
||||
|
||||
$urlBase = sprintf('http://builds-artifacts.piwik.org/ui-tests.master/%s', $buildNumber);
|
||||
$diffviewer = Http::sendHttpRequest($urlBase . "/screenshot-diffs/diffviewer.html", $timeout = 60);
|
||||
|
||||
$dom = new \DOMDocument();
|
||||
$dom->loadHTML($diffviewer);
|
||||
foreach ($dom->getElementsByTagName("tr") as $row) {
|
||||
$columns = $row->getElementsByTagName("td");
|
||||
|
||||
$nameColumn = $columns->item(0);
|
||||
$processedColumn = $columns->item(2);
|
||||
|
||||
$testPlugin = null;
|
||||
if ($nameColumn
|
||||
&& preg_match("/\(for ([a-zA-Z_]+) plugin\)/", $dom->saveXml($nameColumn), $matches)
|
||||
) {
|
||||
$testPlugin = $matches[1];
|
||||
}
|
||||
|
||||
$file = null;
|
||||
if ($processedColumn
|
||||
&& preg_match("/href=\".*\/(.*)\"/", $dom->saveXml($processedColumn), $matches)
|
||||
) {
|
||||
$file = $matches[1];
|
||||
}
|
||||
|
||||
if ($file !== null
|
||||
&& preg_match("/" . $screenshotsRegex . "/", $file)
|
||||
) {
|
||||
if ($testPlugin == null) {
|
||||
$downloadTo = "tests/PHPUnit/UI/expected-ui-screenshots/$file";
|
||||
} else {
|
||||
$downloadTo = "plugins/$testPlugin/tests/UI/expected-ui-screenshots/$file";
|
||||
}
|
||||
|
||||
$output->write("<info>Downloading $file to .$downloadTo...</info>\n");
|
||||
Http::sendHttpRequest("$urlBase/processed-ui-screenshots/$file", $timeout = 60, $userAgent = null,
|
||||
PIWIK_DOCUMENT_ROOT . "/" . $downloadTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
namespace Piwik\Plugins\CoreConsole\Commands;
|
||||
|
||||
use Piwik\Container\StaticContainer;
|
||||
use Piwik\Plugin\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
|
@ -25,7 +26,8 @@ class WatchLog extends ConsoleCommand
|
|||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$cmd = sprintf('tail -f %s/tmp/logs/*.log', PIWIK_DOCUMENT_ROOT);
|
||||
$path = StaticContainer::get('path.tmp') . '/logs/';
|
||||
$cmd = sprintf('tail -f %s*.log', $path);
|
||||
|
||||
$output->writeln('Executing command: ' . $cmd);
|
||||
passthru($cmd);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue