1<?php 2 3/* 4 * This file is part of Component Installer. 5 * 6 * (c) Rob Loach (http://robloach.net) 7 * 8 * For the full copyright and license information, please view the LICENSE.md 9 * file that was distributed with this source code. 10 */ 11 12namespace ComponentInstaller\Process; 13 14use Composer\IO\IOInterface; 15use Composer\Composer; 16use Composer\IO\NullIO; 17use Composer\Package\Dumper\ArrayDumper; 18use ComponentInstaller\Util\Filesystem; 19use Composer\Package\Loader\ArrayLoader; 20 21/** 22 * The base Process type. 23 * 24 * Processes are initialized, and then run during installation. 25 */ 26class Process implements ProcessInterface 27{ 28 /** 29 * @var Composer 30 */ 31 protected $composer; 32 33 /** 34 * @var IOInterface|NullIO 35 */ 36 protected $io; 37 38 /** 39 * @var \Composer\Config 40 */ 41 protected $config; 42 43 /** 44 * @var array 45 */ 46 protected $packages = array(); 47 48 /** 49 * @var string 50 */ 51 protected $componentDir = 'components'; 52 53 /** 54 * @var Filesystem 55 */ 56 protected $fs; 57 58 /** 59 * The Composer installation manager to find Component vendor directories. 60 * @var \Composer\Installer\InstallationManager 61 */ 62 protected $installationManager; 63 64 /** 65 * {@inheritdoc} 66 */ 67 public function __construct(Composer $composer = null, IOInterface $io = null) 68 { 69 $this->composer = isset($composer) ? $composer : new Composer(); 70 $this->io = isset($io) ? $io : new NullIO(); 71 $this->fs = new Filesystem(); 72 $this->installationManager = $this->composer->getInstallationManager(); 73 } 74 75 /** 76 * {@inheritdoc} 77 */ 78 public function init() 79 { 80 // Retrieve the configuration variables. 81 $this->config = $this->composer->getConfig(); 82 if (isset($this->config)) { 83 if ($this->config->has('component-dir')) { 84 $this->componentDir = $this->config->get('component-dir'); 85 } 86 } 87 88 // Get the available packages. 89 $allPackages = array(); 90 /** @var \Composer\Package\Locker $locker */ 91 $locker = $this->composer->getLocker(); 92 if ($locker !== null && $locker->isLocked()) { 93 $lockData = $locker->getLockData(); 94 $allPackages = $lockData['packages']; 95 96 // Also merge in any of the development packages. 97 $dev = isset($lockData['packages-dev']) ? $lockData['packages-dev'] : array(); 98 foreach ($dev as $package) { 99 $allPackages[] = $package; 100 } 101 } 102 103 // Only add those packages that we can reasonably 104 // assume are components into our packages list 105 /** @var \Composer\Package\RootPackageInterface $rootPackage */ 106 $rootPackage = $this->composer->getPackage(); 107 $rootExtras = $rootPackage ? $rootPackage->getExtra() : array(); 108 $customComponents = isset($rootExtras['component']) ? $rootExtras['component'] : array(); 109 foreach ($allPackages as $package) { 110 $name = $package['name']; 111 if (isset($customComponents[$name]) && is_array($customComponents[$name])) { 112 $package['extra'] = array('component' => $customComponents[$name]); 113 $this->packages[] = $package; 114 } 115 else { 116 $extra = isset($package['extra']) ? $package['extra'] : array(); 117 if (isset($extra['component']) && is_array($extra['component'])) { 118 $this->packages[] = $package; 119 } 120 } 121 } 122 123 // Add the root package to the packages list. 124 $root = $this->composer->getPackage(); 125 if ($root) { 126 $dumper = new ArrayDumper(); 127 $package = $dumper->dump($root); 128 $package['is-root'] = true; 129 $this->packages[] = $package; 130 } 131 132 return true; 133 } 134 135 /** 136 * {@inheritdoc} 137 */ 138 public function process() 139 { 140 return false; 141 } 142 143 /** 144 * Retrieves the component name for the component. 145 * 146 * @param string $prettyName 147 * The Composer package name. 148 * @param array $extra 149 * The extra config options sent from Composer. 150 * 151 * @return string 152 * The name of the component, without its vendor name. 153 */ 154 public function getComponentName($prettyName, array $extra = array()) 155 { 156 // Parse the pretty name for the vendor and name. 157 if (strpos($prettyName, '/') !== false) { 158 list($vendor, $name) = explode('/', $prettyName); 159 unset($vendor); 160 } else { 161 // Vendor wasn't found, so default to the pretty name instead. 162 $name = $prettyName; 163 } 164 165 // Allow the component to define its own name. 166 $component = isset($extra['component']) ? $extra['component'] : array(); 167 if (isset($component['name'])) { 168 $name = $component['name']; 169 } 170 171 return $name; 172 } 173 174 /** 175 * Retrieves the component directory. 176 */ 177 public function getComponentDir() 178 { 179 return $this->componentDir; 180 } 181 182 /** 183 * Sets the component directory. 184 * @param string $dir 185 * @return string 186 */ 187 public function setComponentDir($dir) 188 { 189 return $this->componentDir = $dir; 190 } 191 192 /** 193 * Retrieves the given package's vendor directory, where it's installed. 194 * 195 * @param array $package 196 * The package to retrieve the vendor directory for. 197 * @return string 198 */ 199 public function getVendorDir(array $package) 200 { 201 // The root package vendor directory is not handled by getInstallPath(). 202 if (isset($package['is-root']) && $package['is-root'] === true) { 203 $path = getcwd(); 204 205 if (!file_exists($path.DIRECTORY_SEPARATOR.'composer.json')) { 206 for ($temp = __DIR__; strlen($temp) > 3; $temp = dirname($temp)) { 207 if (file_exists($temp.DIRECTORY_SEPARATOR.'composer.json')) { 208 $path = $temp; 209 } 210 } 211 } 212 213 return $path; 214 } 215 216 if (!isset($package['version'])) { 217 $package['version'] = '1.0.0'; 218 } 219 $loader = new ArrayLoader(); 220 $completePackage = $loader->load($package); 221 222 return $this->installationManager->getInstallPath($completePackage); 223 } 224} 225