friendica-addons/advancedcontentfilter/vendor/fxp/composer-asset-plugin/Repository/AbstractAssetsRepository.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);
}