Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
PackagesData.php
Go to the documentation of this file.
1 <?php
6 namespace Magento\Setup\Model;
7 
13 {
17  const COMPOSER_SHOW = 'show';
18  const PARAM_COMMAND = 'command';
19  const PARAM_PACKAGE = 'package';
20  const PARAM_AVAILABLE = '--available';
26  private $composerInformation;
27 
31  protected $urlPrefix = 'https://';
32 
36  private $packagesJson;
37 
41  private $filesystem;
42 
46  private $packagesAuth;
47 
51  private $timeZoneProvider;
52 
56  private $objectManagerProvider;
57 
61  private $metapackagesMap;
62 
73  public function __construct(
74  \Magento\Framework\Composer\ComposerInformation $composerInformation,
75  \Magento\Setup\Model\DateTime\TimeZoneProvider $timeZoneProvider,
76  \Magento\Setup\Model\PackagesAuth $packagesAuth,
77  \Magento\Framework\Filesystem $filesystem,
78  \Magento\Setup\Model\ObjectManagerProvider $objectManagerProvider,
79  \Magento\Setup\Model\Grid\TypeMapper $typeMapper
80  ) {
81  $this->objectManagerProvider = $objectManagerProvider;
82  $this->composerInformation = $composerInformation;
83  $this->timeZoneProvider = $timeZoneProvider;
84  $this->packagesAuth = $packagesAuth;
85  $this->filesystem = $filesystem;
86  $this->typeMapper = $typeMapper;
87  }
88 
93  public function syncPackagesData()
94  {
95  try {
96  $lastSyncData = [];
97  $lastSyncData['lastSyncDate'] = $this->getLastSyncDate();
98  $lastSyncData['packages'] = $this->getPackagesForUpdate();
99  $packagesForInstall = $this->syncPackagesForInstall();
100  $lastSyncData = $this->formatLastSyncData($packagesForInstall, $lastSyncData);
101  return $lastSyncData;
102  } catch (\Exception $e) {
103  throw new \RuntimeException($e->getMessage());
104  }
105  }
106 
112  private function getLastSyncDate()
113  {
114  $directory = $this->filesystem->getDirectoryRead(
116  );
117  if ($directory->isExist(PackagesAuth::PATH_TO_PACKAGES_FILE)) {
118  $fileData = $directory->stat(PackagesAuth::PATH_TO_PACKAGES_FILE);
119  return $fileData['mtime'];
120  }
121  return '';
122  }
123 
131  private function formatLastSyncData($packagesForInstall, $lastSyncData)
132  {
133  $lastSyncData['countOfInstall']
134  = isset($packagesForInstall['packages']) ? count($packagesForInstall['packages']) : 0;
135  $lastSyncData['countOfUpdate'] = isset($lastSyncData['packages']) ? count($lastSyncData['packages']) : 0;
136  $lastSyncData['installPackages'] = $packagesForInstall['packages'];
137  if (isset($lastSyncData['lastSyncDate'])) {
138  $lastSyncData['lastSyncDate'] = $this->formatSyncDate($lastSyncData['lastSyncDate']);
139  }
140  return $lastSyncData;
141  }
142 
149  private function formatSyncDate($syncDate)
150  {
151  $timezone = $this->timeZoneProvider->get();
152  return [
153  'date' => $timezone->formatDateTime(
154  new \DateTime('@' . $syncDate),
155  \IntlDateFormatter::MEDIUM,
156  \IntlDateFormatter::NONE,
157  null,
158  null,
159  'd MMM Y'
160  ),
161  'time' => $timezone->formatDateTime(
162  new \DateTime('@' . $syncDate),
163  \IntlDateFormatter::NONE,
164  \IntlDateFormatter::MEDIUM,
165  null,
166  null,
167  'hh:mma'
168  ),
169  ];
170  }
171 
177  public function getInstalledPackages()
178  {
179  $installedPackages = array_intersect_key(
180  $this->composerInformation->getInstalledMagentoPackages(),
181  $this->composerInformation->getRootPackage()->getRequires()
182  );
183 
184  foreach ($installedPackages as &$package) {
185  $package = $this->addPackageExtraInfo($package);
186  }
187 
188  return $this->filterPackagesList($installedPackages);
189  }
190 
196  public function getPackagesForUpdate()
197  {
198  $packagesForUpdate = [];
199  $packages = $this->getInstalledPackages();
200 
201  foreach ($packages as $package) {
202  $latestProductVersion = $this->getLatestNonDevVersion($package['name']);
203  if ($latestProductVersion && version_compare($latestProductVersion, $package['version'], '>')) {
204  $availableVersions = $this->getPackageAvailableVersions($package['name']);
205  $package['latestVersion'] = $latestProductVersion;
206  $package['versions'] = array_filter($availableVersions, function ($version) use ($package) {
207  return version_compare($version, $package['version'], '>');
208  });
209  $packagesForUpdate[$package['name']] = $package;
210  }
211  }
212 
213  return $packagesForUpdate;
214  }
215 
222  private function getLatestNonDevVersion($package)
223  {
224  $versionParser = new \Composer\Package\Version\VersionParser();
225  foreach ($this->getPackageAvailableVersions($package) as $version) {
226  if ($versionParser->parseStability($version) != 'dev') {
227  return $version;
228  }
229  }
230  return '';
231  }
232 
239  private function getPackagesJson()
240  {
241  if ($this->packagesJson !== null) {
242  return $this->packagesJson;
243  }
244 
245  try {
246  $jsonData = '';
247  $directory = $this->filesystem->getDirectoryRead(
248  \Magento\Framework\App\Filesystem\DirectoryList::COMPOSER_HOME
249  );
250  if ($directory->isExist(PackagesAuth::PATH_TO_PACKAGES_FILE)) {
251  $jsonData = $directory->readFile(PackagesAuth::PATH_TO_PACKAGES_FILE);
252  }
253  $packagesData = json_decode($jsonData, true);
254 
255  $this->packagesJson = isset($packagesData['packages']) ?
256  $packagesData['packages'] :
257  [];
258 
259  return $this->packagesJson;
260  } catch (\Exception $e) {
261  throw new \RuntimeException('Error in reading packages.json');
262  }
263  }
264 
271  private function syncPackagesForInstall()
272  {
273  try {
274  $packagesJson = $this->getPackagesJson();
275  $packages = $this->composerInformation->getInstalledMagentoPackages();
276  $packageNames = array_column($packages, 'name');
277  $installPackages = [];
278  foreach ($packagesJson as $packageName => $package) {
279  if (!empty($package) && isset($package) && is_array($package)) {
280  $package = $this->unsetDevVersions($package);
281  ksort($package);
282  $packageValues = array_values($package);
283  if ($this->isNewUserPackage($packageValues[0], $packageNames)) {
284  uksort($package, 'version_compare');
285  $installPackage = $packageValues[0];
286  $installPackage['versions'] = array_reverse(array_keys($package));
287  $installPackage['name'] = $packageName;
288  $installPackage['vendor'] = explode('/', $packageName)[0];
289  $installPackages[$packageName] = $this->addPackageExtraInfo($installPackage);
290  }
291  }
292  }
293  $packagesForInstall['packages'] = $this->filterPackagesList($installPackages);
294  return $packagesForInstall;
295  } catch (\Exception $e) {
296  throw new \RuntimeException('Error in syncing packages for Install');
297  }
298  }
299 
307  private function getPackageExtraInfo($packageName, $packageVersion)
308  {
309  $packagesJson = $this->getPackagesJson();
310 
311  return isset($packagesJson[$packageName][$packageVersion]['extra']) ?
312  $packagesJson[$packageName][$packageVersion]['extra'] : [];
313  }
314 
321  public function addPackageExtraInfo(array $package)
322  {
323  $extraInfo = $this->getPackageExtraInfo($package['name'], $package['version']);
324 
325  $package['package_title'] = isset($extraInfo['x-magento-ext-title']) ?
326  $extraInfo['x-magento-ext-title'] : $package['name'];
327  $package['package_type'] = isset($extraInfo['x-magento-ext-type']) ? $extraInfo['x-magento-ext-type'] :
328  $this->typeMapper->map($package['type']);
329  $package['package_link'] = isset($extraInfo['x-magento-ext-package-link']) ?
330  $extraInfo['x-magento-ext-package-link'] : '';
331 
332  return $package;
333  }
334 
342  protected function isNewUserPackage($package, $packageNames)
343  {
344  if (!in_array($package['name'], $packageNames) &&
345  in_array($package['type'], $this->composerInformation->getPackagesTypes()) &&
346  strpos($package['name'], 'magento/product-') === false &&
347  strpos($package['name'], 'magento/project-') === false
348  ) {
349  return true;
350  }
351  return false;
352  }
353 
360  protected function unsetDevVersions($package)
361  {
362  foreach ($package as $key => $version) {
363  if (strpos($key, 'dev') !== false) {
364  unset($package[$key]);
365  }
366  }
367  unset($version);
368 
369  return $package;
370  }
371 
378  public function getPackagesForInstall()
379  {
380  $actualInstallPackages = [];
381 
382  try {
383  $installPackages = $this->syncPackagesForInstall()['packages'];
384  $metaPackageByPackage = $this->getMetaPackageForPackage($installPackages);
385  foreach ($installPackages as $package) {
386  $package['metapackage'] =
387  isset($metaPackageByPackage[$package['name']]) ? $metaPackageByPackage[$package['name']] : '';
388  $actualInstallPackages[$package['name']] = $package;
389  $actualInstallPackages[$package['name']]['version'] = $package['versions'][0];
390  }
391  $installPackagesInfo['packages'] = $actualInstallPackages;
392  return $installPackagesInfo;
393  } catch (\Exception $e) {
394  throw new \RuntimeException('Error in getting new packages to install');
395  }
396  }
397 
404  private function filterPackagesList(array $packages)
405  {
406  return array_filter(
407  $packages,
408  function ($item) {
409  return in_array(
410  $item['package_type'],
411  [
412  \Magento\Setup\Model\Grid\TypeMapper::LANGUAGE_PACKAGE_TYPE,
413  \Magento\Setup\Model\Grid\TypeMapper::MODULE_PACKAGE_TYPE,
414  \Magento\Setup\Model\Grid\TypeMapper::EXTENSION_PACKAGE_TYPE,
415  \Magento\Setup\Model\Grid\TypeMapper::THEME_PACKAGE_TYPE,
416  \Magento\Setup\Model\Grid\TypeMapper::METAPACKAGE_PACKAGE_TYPE
417  ]
418  );
419  }
420  );
421  }
422 
429  private function getMetaPackageForPackage($packages)
430  {
431  $result = [];
432  foreach ($packages as $package) {
433  if ($package['type'] == \Magento\Framework\Composer\ComposerInformation::METAPACKAGE_PACKAGE_TYPE) {
434  if (isset($package['require'])) {
435  foreach ($package['require'] as $key => $requirePackage) {
436  $result[$key] = $package['name'];
437  }
438  }
439  }
440  }
441  unset($requirePackage);
442 
443  return $result;
444  }
445 
451  public function getMetaPackagesMap()
452  {
453  if ($this->metapackagesMap === null) {
454  $packages = $this->getPackagesJson();
455  array_walk($packages, function ($packageVersions) {
456  $package = array_shift($packageVersions);
457  if ($package['type'] == \Magento\Framework\Composer\ComposerInformation::METAPACKAGE_PACKAGE_TYPE
458  && isset($package['require'])
459  ) {
460  foreach (array_keys($package['require']) as $key) {
461  $this->metapackagesMap[$key] = $package['name'];
462  }
463  }
464  });
465  }
466 
467  return $this->metapackagesMap;
468  }
469 
477  private function getPackageAvailableVersions($package)
478  {
479  $magentoRepositories = $this->composerInformation->getRootRepositories();
480 
481  // Check we have only one repo.magento.com repository
482  if (count($magentoRepositories) === 1
483  && strpos($magentoRepositories[0], $this->packagesAuth->getCredentialBaseUrl()) !== false
484  ) {
485  $packagesJson = $this->getPackagesJson();
486 
487  if (isset($packagesJson[$package])) {
488  $packageVersions = $packagesJson[$package];
489  uksort($packageVersions, 'version_compare');
490  $packageVersions = array_reverse($packageVersions);
491 
492  return array_keys($packageVersions);
493  }
494  }
495 
496  return $this->getAvailableVersionsFromAllRepositories($package);
497  }
498 
506  private function getAvailableVersionsFromAllRepositories($package)
507  {
508  $versionsPattern = '/^versions\s*\:\s(.+)$/m';
509 
510  $commandParams = [
511  self::PARAM_COMMAND => self::COMPOSER_SHOW,
512  self::PARAM_PACKAGE => $package,
513  self::PARAM_AVAILABLE => true
514  ];
515 
516  $applicationFactory = $this->objectManagerProvider->get()
517  ->get(\Magento\Framework\Composer\MagentoComposerApplicationFactory::class);
519  $application = $applicationFactory->create();
520 
521  $result = $application->runComposerCommand($commandParams);
522  $matches = [];
523  preg_match($versionsPattern, $result, $matches);
524  if (isset($matches[1])) {
525  return explode(', ', $matches[1]);
526  }
527 
528  throw new \RuntimeException(
529  sprintf('Couldn\'t get available versions for package %s', $package)
530  );
531  }
532 }
return false
Definition: gallery.phtml:36
isNewUserPackage($package, $packageNames)
$application
Definition: bootstrap.php:58
__construct(\Magento\Framework\Composer\ComposerInformation $composerInformation, \Magento\Setup\Model\DateTime\TimeZoneProvider $timeZoneProvider, \Magento\Setup\Model\PackagesAuth $packagesAuth, \Magento\Framework\Filesystem $filesystem, \Magento\Setup\Model\ObjectManagerProvider $objectManagerProvider, \Magento\Setup\Model\Grid\TypeMapper $typeMapper)
$filesystem