function ComposerRepository::asyncFetchFile
@phpstan-return PromiseInterface<array<mixed>|true> true if the response was a 304 and the cache is fresh, otherwise it returns the decoded json
File
-
vendor/
composer/ composer/ src/ Composer/ Repository/ ComposerRepository.php, line 1630
Class
- ComposerRepository
- @author Jordi Boggiano <j.boggiano@seld.be>
Namespace
Composer\RepositoryCode
private function asyncFetchFile(string $filename, string $cacheKey, ?string $lastModifiedTime = null) : PromiseInterface {
if ('' === $filename) {
throw new \InvalidArgumentException('$filename should not be an empty string');
}
if (isset($this->packagesNotFoundCache[$filename])) {
return \React\Promise\resolve([
'packages' => [],
]);
}
if (isset($this->freshMetadataUrls[$filename]) && $lastModifiedTime) {
// make it look like we got a 304 response
/** @var PromiseInterface<true> $promise */
$promise = \React\Promise\resolve(true);
return $promise;
}
$httpDownloader = $this->httpDownloader;
$options = $this->options;
if ($this->eventDispatcher) {
$preFileDownloadEvent = new PreFileDownloadEvent(PluginEvents::PRE_FILE_DOWNLOAD, $this->httpDownloader, $filename, 'metadata', [
'repository' => $this,
]);
$preFileDownloadEvent->setTransportOptions($this->options);
$this->eventDispatcher
->dispatch($preFileDownloadEvent->getName(), $preFileDownloadEvent);
$filename = $preFileDownloadEvent->getProcessedUrl();
$options = $preFileDownloadEvent->getTransportOptions();
}
if ($lastModifiedTime) {
if (isset($options['http']['header'])) {
$options['http']['header'] = (array) $options['http']['header'];
}
$options['http']['header'][] = 'If-Modified-Since: ' . $lastModifiedTime;
}
$io = $this->io;
$url = $this->url;
$cache = $this->cache;
$degradedMode =& $this->degradedMode;
$eventDispatcher = $this->eventDispatcher;
/**
* @return array<mixed>|true true if the response was a 304 and the cache is fresh
*/
$accept = function ($response) use ($io, $url, $filename, $cache, $cacheKey, $eventDispatcher) {
// package not found is acceptable for a v2 protocol repository
if ($response->getStatusCode() === 404) {
$this->packagesNotFoundCache[$filename] = true;
return [
'packages' => [],
];
}
$json = (string) $response->getBody();
if ($json === '' && $response->getStatusCode() === 304) {
$this->freshMetadataUrls[$filename] = true;
return true;
}
if ($eventDispatcher) {
$postFileDownloadEvent = new PostFileDownloadEvent(PluginEvents::POST_FILE_DOWNLOAD, null, null, $filename, 'metadata', [
'response' => $response,
'repository' => $this,
]);
$eventDispatcher->dispatch($postFileDownloadEvent->getName(), $postFileDownloadEvent);
}
$data = $response->decodeJson();
HttpDownloader::outputWarnings($io, $url, $data);
$lastModifiedDate = $response->getHeader('last-modified');
$response->collect();
if ($lastModifiedDate) {
$data['last-modified'] = $lastModifiedDate;
$json = JsonFile::encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}
if (!$cache->isReadOnly()) {
$cache->write($cacheKey, $json);
}
$this->freshMetadataUrls[$filename] = true;
return $data;
};
$reject = function ($e) use ($filename, $accept, $io, $url, &$degradedMode, $lastModifiedTime) {
if ($e instanceof TransportException && $e->getStatusCode() === 404) {
$this->packagesNotFoundCache[$filename] = true;
return false;
}
if (!$degradedMode) {
$io->writeError('<warning>' . $url . ' could not be fully loaded (' . $e->getMessage() . '), package information was loaded from the local cache and may be out of date</warning>');
}
$degradedMode = true;
// if the file is in the cache, we fake a 304 Not Modified to allow the process to continue
if ($lastModifiedTime) {
return $accept(new Response([
'url' => $url,
], 304, [], ''));
}
// special error code returned when network is being artificially disabled
if ($e instanceof TransportException && $e->getStatusCode() === 499) {
return $accept(new Response([
'url' => $url,
], 404, [], ''));
}
throw $e;
};
return $httpDownloader->add($filename, $options)
->then($accept, $reject);
}