Download plugins/CoreConsole/Commands/GeneratePluginBase.php from Leon4gr45/matomo: direct link, hf CLI and curl.
- Browser
- Download file 15.5 kB
-
https://huggingface.co/spaces/Leon4gr45/matomo/resolve/main/plugins/CoreConsole/Commands/GeneratePluginBase.php
- Command line
-
hf download hf://spaces/Leon4gr45/matomo/plugins/CoreConsole/Commands/GeneratePluginBase.php
-
curl -L -o GeneratePluginBase.php https://huggingface.co/spaces/Leon4gr45/matomo/resolve/main/plugins/CoreConsole/Commands/GeneratePluginBase.php
15.5 kB
| /** | |
| * Matomo - free/libre analytics platform | |
| * | |
| * @link https://matomo.org | |
| * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later | |
| */ | |
| namespace Piwik\Plugins\CoreConsole\Commands; | |
| use Piwik\Common; | |
| use Piwik\Development; | |
| use Piwik\Filesystem; | |
| use Piwik\Plugin\ConsoleCommand; | |
| use Piwik\Plugin\Dependency; | |
| use Piwik\Plugin\Manager; | |
| use Piwik\Version; | |
| use Piwik\SettingsPiwik; | |
| use Piwik\Exception\NotGitInstalledException; | |
| abstract class GeneratePluginBase extends ConsoleCommand | |
| { | |
| protected function doInitialize(): void | |
| { | |
| $this->throwErrorIfNotGitInstalled(); | |
| } | |
| public function isEnabled() | |
| { | |
| return Development::isEnabled(); | |
| } | |
| public function getPluginPath($pluginName) | |
| { | |
| return Manager::getPluginDirectory($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($pluginNameOrCore, $fileName, $content) | |
| { | |
| 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 | |
| * @param string $translationKey Optional, by default the key will be generated automatically | |
| * @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, $translationKey = '') | |
| { | |
| $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(); | |
| } | |
| if (!empty($translationKey)) { | |
| $key = $translationKey; | |
| } else { | |
| $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) | |
| { | |
| $output = $this->getOutput(); | |
| $pluginJsonPath = $this->getPluginPath($pluginName) . '/plugin.json'; | |
| $relativePluginJson = Manager::getPluginDirectory($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; | |
| $nextMajorVersion = (int) substr($piwikVersion, 0, strpos($piwikVersion, '.')) + 1; | |
| $secondPartPiwikVersionRequire = ',<' . $nextMajorVersion . '.0.0-b1'; | |
| if (false === strpos($piwikVersion, '-')) { | |
| // see https://github.com/composer/composer/issues/4080 we need to specify -stable otherwise it would match | |
| // $piwikVersion-dev meaning it would also match all pre-released. However, we only want to match a stable | |
| // release | |
| $piwikVersion .= '-stable'; | |
| } | |
| $newRequiredVersion = sprintf('>=%s,<%d.0.0-b1', $piwikVersion, $nextMajorVersion); | |
| if (!empty($pluginJson['require']['piwik'])) { | |
| $pluginJson['require']['matomo'] = $pluginJson['require']['piwik']; | |
| unset($pluginJson['require']['piwik']); | |
| } | |
| if (!empty($pluginJson['require']['matomo'])) { | |
| $requiredVersion = trim($pluginJson['require']['matomo']); | |
| if ($requiredVersion === $newRequiredVersion) { | |
| // there is nothing to updated | |
| return; | |
| } | |
| // our generated versions look like ">=2.25.4,<3.0.0-b1". | |
| // We only updated the Piwik version in the first part if the piwik version looks like that or if it has only | |
| // one piwik version defined. In all other cases, eg user uses || etc we do not update it as user has customized | |
| // the piwik version. | |
| foreach (['<>','!=', '<=','==', '^'] as $comparison) { | |
| if (strpos($requiredVersion, $comparison) === 0) { | |
| // user is using custom piwik version require, we do not overwrite anything. | |
| return; | |
| } | |
| } | |
| if (strpos($requiredVersion, '||') !== false || strpos($requiredVersion, ' ') !== false) { | |
| // user is using custom piwik version require, we do not overwrite anything. | |
| return; | |
| } | |
| $requiredPiwikVersions = explode(',', (string) $requiredVersion); | |
| $numRequiredPiwikVersions = count($requiredPiwikVersions); | |
| if ($numRequiredPiwikVersions > 2) { | |
| // user is using custom piwik version require, we do not overwrite anything. | |
| return; | |
| } | |
| if ( | |
| $numRequiredPiwikVersions === 2 && | |
| !Common::stringEndsWith($requiredVersion, $secondPartPiwikVersionRequire) | |
| ) { | |
| // user is using custom piwik version require, we do not overwrite anything | |
| return; | |
| } | |
| // if only one piwik version is defined we update it to make sure it does now specify an upper version limit | |
| $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']['matomo'] = $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 | |
| * @param array $replace array(key => value) $key will be replaced by $value in all templates | |
| * @param array $whitelistFiles If not empty, only given files/directories will be copied. | |
| * For instance array('/Controller.php', '/templates', '/templates/index.twig') | |
| */ | |
| protected function copyTemplateToPlugin($templateFolder, $pluginName, array $replace = [], $whitelistFiles = []) | |
| { | |
| $replace['PLUGINNAME'] = $pluginName; | |
| $files = array_merge( | |
| Filesystem::globr($templateFolder, '*'), | |
| // Also copy files starting with . such as .gitignore | |
| Filesystem::globr($templateFolder, '.*') | |
| ); | |
| foreach ($files as $file) { | |
| $fileNamePlugin = str_replace($templateFolder, '', $file); | |
| if (!empty($whitelistFiles) && !in_array($fileNamePlugin, $whitelistFiles)) { | |
| continue; | |
| } | |
| if (is_dir($file)) { | |
| $fileNamePlugin = $this->replaceContent($replace, $fileNamePlugin); | |
| $this->createFolderWithinPluginIfNotExists($pluginName, $fileNamePlugin); | |
| } else { | |
| $template = file_get_contents($file); | |
| $template = $this->replaceContent($replace, $template); | |
| $fileNamePlugin = $this->replaceContent($replace, $fileNamePlugin); | |
| $this->createFileWithinPluginIfNotExists($pluginName, $fileNamePlugin, $template); | |
| } | |
| } | |
| } | |
| protected function getPluginNames() | |
| { | |
| $pluginNames = array(); | |
| foreach (Manager::getPluginsDirectories() as $pluginsDir) { | |
| $pluginDirs = \_glob($pluginsDir . '*', GLOB_ONLYDIR); | |
| foreach ($pluginDirs as $pluginDir) { | |
| $pluginNames[] = basename($pluginDir); | |
| } | |
| } | |
| return $pluginNames; | |
| } | |
| protected function getPluginNamesHavingNotSpecificFile($filename) | |
| { | |
| $pluginNames = array(); | |
| foreach (Manager::getPluginsDirectories() as $pluginsDir) { | |
| $pluginDirs = \_glob($pluginsDir . '*', GLOB_ONLYDIR); | |
| foreach ($pluginDirs as $pluginDir) { | |
| if (!file_exists($pluginDir . '/' . $filename)) { | |
| $pluginNames[] = basename($pluginDir); | |
| } | |
| } | |
| } | |
| return $pluginNames; | |
| } | |
| /** | |
| * @return string | |
| * @throws \RuntimeException | |
| */ | |
| protected function askPluginNameAndValidate($pluginNames, $invalidArgumentException) | |
| { | |
| $input = $this->getInput(); | |
| $validate = function ($pluginName) use ($pluginNames, $invalidArgumentException) { | |
| if (!in_array($pluginName, $pluginNames)) { | |
| throw new \InvalidArgumentException($invalidArgumentException); | |
| } | |
| return $pluginName; | |
| }; | |
| $pluginName = $input->getOption('pluginname'); | |
| if (empty($pluginName)) { | |
| $pluginName = $this->askAndValidate('Enter the name of your plugin: ', $validate, false, $pluginNames); | |
| } else { | |
| $validate($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; | |
| } | |
| protected function throwErrorIfNotGitInstalled() | |
| { | |
| if (!SettingsPiwik::isGitDeployment()) { | |
| $url = 'https://developer.matomo.org/guides/getting-started-part-1'; | |
| throw new NotGitInstalledException( | |
| "This development feature requires Matomo to be checked out from git. For more information please visit {$url}." | |
| ); | |
| } | |
| } | |
| } | |