349 lines
9.3 KiB
PHP
349 lines
9.3 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of the Fxp Composer Asset Plugin package.
|
|
*
|
|
* (c) François Pluchino <francois.pluchino@gmail.com>
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Fxp\Composer\AssetPlugin\Repository;
|
|
|
|
use Composer\Config;
|
|
use Composer\DependencyResolver\Pool;
|
|
use Composer\Downloader\TransportException;
|
|
use Composer\EventDispatcher\EventDispatcher;
|
|
use Composer\IO\IOInterface;
|
|
use Composer\Json\JsonFile;
|
|
use Composer\Repository\ComposerRepository;
|
|
use Composer\Repository\RepositoryManager;
|
|
use Fxp\Composer\AssetPlugin\Assets;
|
|
use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
|
|
|
|
/**
|
|
* Abstract assets repository.
|
|
*
|
|
* @author François Pluchino <francois.pluchino@gmail.com>
|
|
*/
|
|
abstract class AbstractAssetsRepository extends ComposerRepository
|
|
{
|
|
/**
|
|
* @var AssetTypeInterface
|
|
*/
|
|
protected $assetType;
|
|
|
|
/**
|
|
* @var AssetVcsRepository[]
|
|
*/
|
|
protected $repos;
|
|
|
|
/**
|
|
* @var bool
|
|
*/
|
|
protected $searchable;
|
|
|
|
/**
|
|
* @var bool
|
|
*/
|
|
protected $fallbackProviders;
|
|
|
|
/**
|
|
* @var RepositoryManager
|
|
*/
|
|
protected $repositoryManager;
|
|
|
|
/**
|
|
* @var AssetRepositoryManager
|
|
*/
|
|
protected $assetRepositoryManager;
|
|
|
|
/**
|
|
* @var VcsPackageFilter
|
|
*/
|
|
protected $packageFilter;
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param array $repoConfig
|
|
* @param IOInterface $io
|
|
* @param Config $config
|
|
* @param EventDispatcher $eventDispatcher
|
|
*/
|
|
public function __construct(array $repoConfig, IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null)
|
|
{
|
|
$repoConfig = array_merge($repoConfig, array(
|
|
'url' => $this->getUrl(),
|
|
));
|
|
$this->assetRepositoryManager = $repoConfig['asset-repository-manager'];
|
|
$this->repositoryManager = $this->assetRepositoryManager->getRepositoryManager();
|
|
|
|
parent::__construct($repoConfig, $io, $config, $eventDispatcher);
|
|
|
|
$this->assetType = Assets::createType($this->getType());
|
|
$this->lazyProvidersUrl = $this->getPackageUrl();
|
|
$this->providersUrl = $this->lazyProvidersUrl;
|
|
$this->searchUrl = $this->getSearchUrl();
|
|
$this->hasProviders = true;
|
|
$this->packageFilter = isset($repoConfig['vcs-package-filter'])
|
|
? $repoConfig['vcs-package-filter']
|
|
: null;
|
|
$this->repos = array();
|
|
$this->searchable = (bool) $this->getOption($repoConfig['asset-options'], 'searchable', true);
|
|
$this->fallbackProviders = false;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function search($query, $mode = 0, $type = null)
|
|
{
|
|
if (!$this->searchable) {
|
|
return array();
|
|
}
|
|
|
|
$url = str_replace('%query%', urlencode(Util::cleanPackageName($query)), $this->searchUrl);
|
|
$hostname = (string) parse_url($url, PHP_URL_HOST) ?: $url;
|
|
$json = (string) $this->rfs->getContents($hostname, $url, false);
|
|
$data = JsonFile::parseJson($json, $url);
|
|
$results = array();
|
|
|
|
/* @var array $item */
|
|
foreach ($data as $item) {
|
|
$results[] = $this->createSearchItem($item);
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function whatProvides(Pool $pool, $name, $bypassFilters = false)
|
|
{
|
|
if (null !== $provides = $this->findWhatProvides($name)) {
|
|
return $provides;
|
|
}
|
|
|
|
try {
|
|
$repoName = Util::convertAliasName($name);
|
|
$packageName = Util::cleanPackageName($repoName);
|
|
$packageUrl = $this->buildPackageUrl($packageName);
|
|
$cacheName = $packageName.'-'.sha1($packageName).'-package.json';
|
|
$data = $this->fetchFile($packageUrl, $cacheName);
|
|
$repo = $this->createVcsRepositoryConfig($data, Util::cleanPackageName($name));
|
|
$repo['asset-repository-manager'] = $this->assetRepositoryManager;
|
|
$repo['vcs-package-filter'] = $this->packageFilter;
|
|
$repo['vcs-driver-options'] = Util::getArrayValue($this->repoConfig, 'vcs-driver-options', array());
|
|
|
|
Util::addRepository($this->io, $this->repositoryManager, $this->repos, $name, $repo, $pool);
|
|
|
|
$this->providers[$name] = array();
|
|
} catch (\Exception $ex) {
|
|
$this->whatProvidesManageException($pool, $name, $ex);
|
|
}
|
|
|
|
return $this->providers[$name];
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getMinimalPackages()
|
|
{
|
|
return array();
|
|
}
|
|
|
|
/**
|
|
* Build the package url.
|
|
*
|
|
* @param string $packageName The package name
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function buildPackageUrl($packageName)
|
|
{
|
|
return str_replace('%package%', $packageName, $this->lazyProvidersUrl);
|
|
}
|
|
|
|
/**
|
|
* Finds what provides in cache or return empty array if the
|
|
* name is not a asset package.
|
|
*
|
|
* @param string $name
|
|
*
|
|
* @return array|null
|
|
*/
|
|
protected function findWhatProvides($name)
|
|
{
|
|
$assetPrefix = $this->assetType->getComposerVendorName().'/';
|
|
|
|
if (false === strpos($name, $assetPrefix)) {
|
|
return array();
|
|
}
|
|
|
|
if (isset($this->providers[$name])) {
|
|
return $this->providers[$name];
|
|
}
|
|
|
|
$data = null;
|
|
if ($this->hasVcsRepository($name)) {
|
|
$this->providers[$name] = array();
|
|
$data = $this->providers[$name];
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Checks if the package vcs repository is already include in repository manager.
|
|
*
|
|
* @param string $name The package name of the vcs repository
|
|
*
|
|
* @return bool
|
|
*/
|
|
protected function hasVcsRepository($name)
|
|
{
|
|
foreach ($this->repositoryManager->getRepositories() as $mRepo) {
|
|
if ($mRepo instanceof AssetVcsRepository
|
|
&& $name === $mRepo->getComposerPackageName()) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
protected function loadRootServerFile()
|
|
{
|
|
return array(
|
|
'providers' => array(),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Gets the option.
|
|
*
|
|
* @param array $options The options
|
|
* @param string $key The key
|
|
* @param mixed $default The default value
|
|
*
|
|
* @return mixed The option value or default value if key is not found
|
|
*/
|
|
protected function getOption(array $options, $key, $default = null)
|
|
{
|
|
if (array_key_exists($key, $options)) {
|
|
return $options[$key];
|
|
}
|
|
|
|
return $default;
|
|
}
|
|
|
|
/**
|
|
* Creates the search result item.
|
|
*
|
|
* @param array $item The item
|
|
*
|
|
* @return array An array('name' => '...', 'description' => '...')
|
|
*/
|
|
protected function createSearchItem(array $item)
|
|
{
|
|
return array(
|
|
'name' => $this->assetType->getComposerVendorName().'/'.$item['name'],
|
|
'description' => null,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Manage exception for "whatProvides" method.
|
|
*
|
|
* @param Pool $pool
|
|
* @param string $name
|
|
* @param \Exception $exception
|
|
*
|
|
* @throws \Exception When exception is not a TransportException instance
|
|
*/
|
|
protected function whatProvidesManageException(Pool $pool, $name, \Exception $exception)
|
|
{
|
|
if ($exception instanceof TransportException) {
|
|
$this->fallbackWathProvides($pool, $name, $exception);
|
|
|
|
return;
|
|
}
|
|
|
|
throw $exception;
|
|
}
|
|
|
|
/**
|
|
* Searchs if the registry has a package with the same name exists with a
|
|
* different camelcase.
|
|
*
|
|
* @param Pool $pool
|
|
* @param string $name
|
|
* @param TransportException $ex
|
|
*/
|
|
protected function fallbackWathProvides(Pool $pool, $name, TransportException $ex)
|
|
{
|
|
$providers = array();
|
|
|
|
if (404 === $ex->getCode() && !$this->fallbackProviders) {
|
|
$this->fallbackProviders = true;
|
|
$repoName = Util::convertAliasName($name);
|
|
$results = $this->search($repoName);
|
|
|
|
foreach ($results as $item) {
|
|
if ($name === strtolower($item['name'])) {
|
|
$providers = $this->whatProvides($pool, $item['name']);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->fallbackProviders = false;
|
|
$this->providers[$name] = $providers;
|
|
}
|
|
|
|
/**
|
|
* Gets the asset type name.
|
|
*
|
|
* @return string
|
|
*/
|
|
abstract protected function getType();
|
|
|
|
/**
|
|
* Gets the URL of repository.
|
|
*
|
|
* @return string
|
|
*/
|
|
abstract protected function getUrl();
|
|
|
|
/**
|
|
* Gets the URL for get the package information.
|
|
*
|
|
* @return string
|
|
*/
|
|
abstract protected function getPackageUrl();
|
|
|
|
/**
|
|
* Gets the URL for get the search result.
|
|
*
|
|
* @return string
|
|
*/
|
|
abstract protected function getSearchUrl();
|
|
|
|
/**
|
|
* Creates a config of vcs repository.
|
|
*
|
|
* @param array $data The repository config
|
|
* @param string $registryName The package name in asset registry
|
|
*
|
|
* @return array An array('type' => '...', 'url' => '...')
|
|
*/
|
|
abstract protected function createVcsRepositoryConfig(array $data, $registryName = null);
|
|
}
|