* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Fxp\Composer\AssetPlugin\Package\Loader; use Composer\Downloader\TransportException; use Composer\IO\IOInterface; use Composer\Package\CompletePackageInterface; use Composer\Package\Loader\LoaderInterface; use Composer\Repository\Vcs\VcsDriverInterface; use Fxp\Composer\AssetPlugin\Exception\InvalidArgumentException; use Fxp\Composer\AssetPlugin\Package\LazyPackageInterface; use Fxp\Composer\AssetPlugin\Repository\AssetRepositoryManager; use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface; /** * Lazy loader for asset package. * * @author François Pluchino */ class LazyAssetPackageLoader implements LazyLoaderInterface { /** * @var string */ protected $type; /** * @var string */ protected $identifier; /** * @var array */ protected $packageData; /** * @var AssetTypeInterface */ protected $assetType; /** * @var LoaderInterface */ protected $loader; /** * @var VcsDriverInterface */ protected $driver; /** * @var IOInterface */ protected $io; /** * @var AssetRepositoryManager */ protected $assetRepositoryManager; /** * @var bool */ protected $verbose; /** * @var array */ protected $cache; /** * Constructor. * * @param string $identifier * @param string $type * @param array $packageData */ public function __construct($type, $identifier, array $packageData) { $this->identifier = $identifier; $this->type = $type; $this->packageData = $packageData; $this->verbose = false; $this->cache = array(); } /** * Sets the asset type. * * @param AssetTypeInterface $assetType */ public function setAssetType(AssetTypeInterface $assetType) { $this->assetType = $assetType; } /** * Sets the laoder. * * @param LoaderInterface $loader */ public function setLoader(LoaderInterface $loader) { $this->loader = $loader; } /** * Sets the driver. * * @param VcsDriverInterface $driver */ public function setDriver(VcsDriverInterface $driver) { $this->driver = $driver; } /** * Sets the IO. * * @param IOInterface $io */ public function setIO(IOInterface $io) { $this->io = $io; $this->verbose = $io->isVerbose(); } /** * Sets the asset repository manager. * * @param AssetRepositoryManager $assetRepositoryManager The asset repository manager */ public function setAssetRepositoryManager(AssetRepositoryManager $assetRepositoryManager) { $this->assetRepositoryManager = $assetRepositoryManager; } /** * {@inheritdoc} */ public function load(LazyPackageInterface $package) { if (isset($this->cache[$package->getUniqueName()])) { return $this->cache[$package->getUniqueName()]; } $this->validateConfig(); $filename = $this->assetType->getFilename(); $msg = 'Reading '.$filename.' of '.$package->getName().' ('.$package->getPrettyVersion().')'; if ($this->verbose) { $this->io->write($msg); } else { $this->io->overwrite($msg, false); } $realPackage = $this->loadRealPackage($package); $this->cache[$package->getUniqueName()] = $realPackage; if (!$this->verbose) { $this->io->overwrite('', false); } return $realPackage; } /** * Validates the class config. * * @throws InvalidArgumentException When the property of this class is not defined */ protected function validateConfig() { foreach (array('assetType', 'loader', 'driver', 'io') as $property) { if (null === $this->$property) { throw new InvalidArgumentException(sprintf('The "%s" property must be defined', $property)); } } } /** * Loads the real package. * * @param LazyPackageInterface $package * * @return CompletePackageInterface|false */ protected function loadRealPackage(LazyPackageInterface $package) { $realPackage = false; try { $data = $this->driver->getComposerInformation($this->identifier); $valid = is_array($data); $data = $this->preProcess($this->driver, $this->validateData($data), $this->identifier); if ($this->verbose) { $this->io->write('Importing '.($valid ? '' : 'empty ').$this->type.' '.$data['version'].' ('.$data['version_normalized'].')'); } /* @var CompletePackageInterface $realPackage */ $realPackage = $this->loader->load($data); } catch (\Exception $e) { if ($this->verbose) { $filename = $this->assetType->getFilename(); $this->io->write('<'.$this->getIoTag().'>Skipped '.$this->type.' '.$package->getPrettyVersion().', '.($e instanceof TransportException ? 'no '.$filename.' file was found' : $e->getMessage()).'getIoTag().'>'); } } $this->driver->cleanup(); return $realPackage; } /** * @param array|bool $data * * @return array */ protected function validateData($data) { return is_array($data) ? $data : array(); } /** * Gets the tag name for IO. * * @return string */ protected function getIoTag() { return 'branch' === $this->type ? 'error' : 'warning'; } /** * Pre process the data of package before the conversion to Package instance. * * @param VcsDriverInterface $driver * @param array $data * @param string $identifier * * @return array */ protected function preProcess(VcsDriverInterface $driver, array $data, $identifier) { $vcsRepos = array(); $data = array_merge($data, $this->packageData); $data = $this->assetType->getPackageConverter()->convert($data, $vcsRepos); $this->addRepositories($vcsRepos); if (!isset($data['dist'])) { $data['dist'] = $driver->getDist($identifier); } if (!isset($data['source'])) { $data['source'] = $driver->getSource($identifier); } return $this->assetRepositoryManager->solveResolutions((array) $data); } /** * Dispatches the vcs repositories event. * * @param array $vcsRepositories */ protected function addRepositories(array $vcsRepositories) { if (null !== $this->assetRepositoryManager) { $this->assetRepositoryManager->addRepositories($vcsRepositories); } } }