Problem.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <?php
  2. /*
  3. * This file is part of Composer.
  4. *
  5. * (c) Nils Adermann <naderman@naderman.de>
  6. * Jordi Boggiano <j.boggiano@seld.be>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Composer\DependencyResolver;
  12. /**
  13. * Represents a problem detected while solving dependencies
  14. *
  15. * @author Nils Adermann <naderman@naderman.de>
  16. */
  17. class Problem
  18. {
  19. /**
  20. * A set of reasons for the problem, each is a rule or a job and a rule
  21. * @var array
  22. */
  23. protected $reasons;
  24. /**
  25. * Add a rule as a reason
  26. *
  27. * @param Rule $rule A rule which is a reason for this problem
  28. */
  29. public function addRule(Rule $rule)
  30. {
  31. $this->addReason($rule->getId(), array(
  32. 'rule' => $rule,
  33. 'job' => $rule->getJob(),
  34. ));
  35. }
  36. /**
  37. * Retrieve all reasons for this problem
  38. *
  39. * @return array The problem's reasons
  40. */
  41. public function getReasons()
  42. {
  43. return $this->reasons;
  44. }
  45. /**
  46. * A human readable textual representation of the problem's reasons
  47. */
  48. public function __toString()
  49. {
  50. if (count($this->reasons) === 1) {
  51. reset($this->reasons);
  52. $reason = current($this->reasons);
  53. $rule = $reason['rule'];
  54. $job = $reason['job'];
  55. if ($job && $job['cmd'] === 'install' && empty($job['packages'])) {
  56. // handle php extensions
  57. if (0 === stripos($job['packageName'], 'ext-')) {
  58. $ext = substr($job['packageName'], 4);
  59. $error = extension_loaded($ext) ? 'has the wrong version ('.phpversion($ext).') installed' : 'is missing from your system';
  60. return 'The requested PHP extension '.$job['packageName'].$this->constraintToText($job['constraint']).' '.$error.'.';
  61. }
  62. return 'The requested package '.$job['packageName'].$this->constraintToText($job['constraint']).' could not be found.';
  63. }
  64. }
  65. $messages = array("Problem caused by:");
  66. foreach ($this->reasons as $reason) {
  67. $rule = $reason['rule'];
  68. $job = $reason['job'];
  69. if ($job) {
  70. $messages[] = $this->jobToText($job);
  71. } elseif ($rule) {
  72. if ($rule instanceof Rule) {
  73. $messages[] = $rule->toHumanReadableString();
  74. }
  75. }
  76. }
  77. return implode("\n\t\t\t- ", $messages);
  78. }
  79. /**
  80. * Store a reason descriptor but ignore duplicates
  81. *
  82. * @param string $id A canonical identifier for the reason
  83. * @param string $reason The reason descriptor
  84. */
  85. protected function addReason($id, $reason)
  86. {
  87. if (!isset($this->reasons[$id])) {
  88. $this->reasons[$id] = $reason;
  89. }
  90. }
  91. /**
  92. * Turns a job into a human readable description
  93. *
  94. * @param array $job
  95. * @return string
  96. */
  97. protected function jobToText($job)
  98. {
  99. switch ($job['cmd']) {
  100. case 'install':
  101. if (!$job['packages']) {
  102. return 'No package found to satisfy install request for '.$job['packageName'].$this->constraintToText($job['constraint']);
  103. }
  104. return 'Installation request for '.$job['packageName'].$this->constraintToText($job['constraint']).': Satisfiable by ['.$this->getPackageList($job['packages']).'].';
  105. case 'update':
  106. return 'Update request for '.$job['packageName'].$this->constraintToText($job['constraint']).'.';
  107. case 'remove':
  108. return 'Removal request for '.$job['packageName'].$this->constraintToText($job['constraint']).'';
  109. }
  110. return 'Job(cmd='.$job['cmd'].', target='.$job['packageName'].', packages=['.$this->packageList($job['packages']).'])';
  111. }
  112. protected function getPackageList($packages)
  113. {
  114. return implode(', ', array_map(function ($package) {
  115. return $package->getPrettyString();
  116. },
  117. $packages
  118. ));
  119. }
  120. /**
  121. * Turns a constraint into text usable in a sentence describing a job
  122. *
  123. * @param LinkConstraint $constraint
  124. * @return string
  125. */
  126. protected function constraintToText($constraint)
  127. {
  128. return ($constraint) ? ' '.$constraint : '';
  129. }
  130. }