'2.1.3' ] * * @var string[] */ private $versionsLocalCache = []; /** * For example [ ModuleName => '2.1.3' ] * * @var string[] */ private $metapackageVersions = []; /** * @var \Magento\Framework\App\CacheInterface */ private $cache; /** * @var \Plumrocket\Base\Model\Extension\GetModuleName */ private $getModuleName; /** * @var \Magento\Framework\Config\DataInterface */ private $extensionsConfig; /** * @var \Magento\Framework\Composer\ComposerInformation */ private $composerInformation; /** * @param \Magento\Framework\App\Utility\Files $files * @param \Magento\Framework\App\CacheInterface $cache * @param \Plumrocket\Base\Model\Extension\GetModuleName $getModuleName * @param \Magento\Framework\Config\DataInterface $extensionsConfig * @param \Magento\Framework\Composer\ComposerInformation $composerInformation */ public function __construct( Files $files, CacheInterface $cache, GetModuleName $getModuleName, DataInterface $extensionsConfig, ComposerInformation $composerInformation ) { $this->files = $files; $this->cache = $cache; $this->getModuleName = $getModuleName; $this->extensionsConfig = $extensionsConfig; $this->composerInformation = $composerInformation; } /** * Get module version from composer.json. * * @param string $moduleName * @return string */ public function execute($moduleName) { $moduleName = $this->getModuleName->execute($moduleName); if ($this->shouldUseMetapackage($moduleName)) { return $this->getMetapackageVersion($moduleName); } return $this->getModuleVersion($moduleName); } /** * Check if module is part of metapackage. * * For metapackage module we should use version from metapackage, not from specific module. * * @param string $moduleName e.g. SocialLoginFree * @return bool */ private function shouldUseMetapackage(string $moduleName): bool { return (bool) $this->extensionsConfig->get("$moduleName/metapackage/composer_name"); } /** * Get version of module. * * @param string $moduleName e.g. SocialLoginFree * @return string */ private function getModuleVersion(string $moduleName): string { if (! isset($this->versionsLocalCache[$moduleName]) || ! $this->versionsLocalCache[$moduleName]) { $moduleVersions = $this->getFromCache(self::CACHE_IDENTIFIER); if (! isset($moduleVersions[$moduleName])) { $this->versionsLocalCache[$moduleName] = ''; $composerFilePaths = $this->files->getComposerFiles(ComponentRegistrar::MODULE); $version = $this->getModuleVersionFromAppCode($composerFilePaths, "Plumrocket/$moduleName"); if ($version) { $this->versionsLocalCache[$moduleName] = $version; } else { $versions = $this->getModulesVersionFromVendorFolder($composerFilePaths); $this->versionsLocalCache = array_merge($this->versionsLocalCache, $versions); } $moduleVersions = array_merge($moduleVersions, $this->versionsLocalCache); $this->saveToCache(self::CACHE_IDENTIFIER, $moduleVersions); } $this->versionsLocalCache = $moduleVersions; } return $this->versionsLocalCache[$moduleName]; } /** * Get version of metapackage * * @param string $moduleName * @return string */ private function getMetapackageVersion(string $moduleName): string { if (! isset($this->metapackageVersions[$moduleName]) || ! $this->metapackageVersions[$moduleName]) { $moduleVersions = $this->getFromCache(self::METAPACKAGE_CACHE_IDENTIFIER); if (! isset($moduleVersions[$moduleName])) { $this->metapackageVersions[$moduleName] = ''; $composerFilePaths = $this->files->getComposerFiles(ComponentRegistrar::MODULE); $version = $this->getMetapackageVersionFromAppCode($composerFilePaths, $moduleName); if ($version) { $this->metapackageVersions[$moduleName] = $version; } else { $this->metapackageVersions[$moduleName] = $this->getMetapackageVersionFromComposer($moduleName); } $moduleVersions = array_merge($moduleVersions, $this->metapackageVersions); $this->saveToCache(self::METAPACKAGE_CACHE_IDENTIFIER, $moduleVersions); } $this->metapackageVersions = $moduleVersions; } return $this->metapackageVersions[$moduleName]; } /** * Get versions from app/code/Plumrocket * * @param array $composerFilePaths * @param string $modulePathName * @return mixed|string */ private function getModuleVersionFromAppCode(array $composerFilePaths, string $modulePathName) { foreach ($composerFilePaths as $path => $absolutePath) { if (false !== strpos($path, "code/$modulePathName/composer.json")) { return $this->extractDataFromComposerJson($path)['version']; } } return ''; } /** * Get versions from vendor/plumrocket/ * * @param array $composerFilePaths * @return string[] */ private function getModulesVersionFromVendorFolder(array $composerFilePaths): array { $versions = []; foreach ($composerFilePaths as $path => $absolutePath) { if (false !== strpos($path, 'plumrocket')) { $data = $this->extractDataFromComposerJson($path); if ($data['version']) { $versions[$data['name']] = $data['version']; } } } return $versions; } /** * Read and parse composer.json * * @param string $path * @return string[] */ public function extractDataFromComposerJson(string $path): array { if (0 === strpos(trim($path, '/'), 'app') || 0 === strpos(trim($path, '/'), 'vendor') ) { $path = BP . DIRECTORY_SEPARATOR . trim($path, '/'); } $result = ['version' => '', 'name' => '']; if (! file_exists($path)) { return $result; } $content = file_get_contents($path); if ($content) { $jsonContent = json_decode($content, true); if (! empty($jsonContent['version'])) { $result['version'] = $jsonContent['version']; } if (! empty($jsonContent['autoload']['psr-4'])) { $directoryPath = trim(array_keys($jsonContent['autoload']['psr-4'])[0], '\\'); $result['name'] = explode('\\', $directoryPath)[1]; } } return $result; } /** * Get metapackage version from root magento composer.json file. * * Installing metapackage via composer do not create folder with composer.json file. * * @param string $moduleName * @return string */ private function getMetapackageVersionFromComposer(string $moduleName): string { $composerName = $this->extensionsConfig->get("$moduleName/metapackage/composer_name"); $package = $this->composerInformation->getInstalledMagentoPackages()[$composerName] ?? []; return $package['version'] ?? ''; } /** * Find metapackage in app/code/Plumrocket and get its version. * * @param array $composerFilePaths * @param string $moduleName * @return string */ private function getMetapackageVersionFromAppCode(array $composerFilePaths, string $moduleName): string { $directory = (string) $this->extensionsConfig->get("$moduleName/metapackage/directory"); foreach ($composerFilePaths as $path => $absolutePath) { if (false !== strpos($path, "code/Plumrocket/$moduleName/composer.json")) { $path = str_replace("Plumrocket/$moduleName", "Plumrocket/$directory", $path); return $this->extractDataFromComposerJson($path)['version']; } } return ''; } /** * Get versions from cache. * * @param string $key * @return array */ private function getFromCache(string $key): array { $moduleVersionsJson = $this->cache->load($key); if ($moduleVersionsJson) { $moduleVersions = (array) json_decode($moduleVersionsJson, true); } else { $moduleVersions = []; } return $moduleVersions; } /** * Cache versions as it is heavy operation. * * @param string $key * @param array $moduleVersions */ private function saveToCache(string $key, array $moduleVersions): void { $this->cache->save(json_encode($moduleVersions), $key, [Config::CACHE_TAG]); } }