Skip to content

Commit

Permalink
feat: add method to fetch package info from new composer 2 api and ov…
Browse files Browse the repository at this point in the history
…erride getComposer to use new api
  • Loading branch information
JellyBellyDev committed Dec 17, 2021
1 parent ca668d4 commit 179847d
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 40 deletions.
8 changes: 8 additions & 0 deletions examples/getComposer.php
@@ -0,0 +1,8 @@
<?php

require __DIR__.'/../vendor/autoload.php';

$client = new Packagist\Api\Client();
$package = $client->getComposer('sylius/sylius');

var_export($package);
8 changes: 8 additions & 0 deletions examples/getComposerLite.php
@@ -0,0 +1,8 @@
<?php

require __DIR__.'/../vendor/autoload.php';

$client = new Packagist\Api\Client();
$package = $client->getComposerLite('sylius/sylius');

var_export($package);
64 changes: 45 additions & 19 deletions spec/Packagist/Api/ClientSpec.php
Expand Up @@ -6,6 +6,7 @@

use GuzzleHttp\Client as HttpClient;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\Stream;
use Packagist\Api\Client;
use Packagist\Api\Result\Factory;
use PhpSpec\ObjectBehavior;
Expand All @@ -17,15 +18,16 @@ public function let(HttpClient $client, Factory $factory)
$this->beConstructedWith($client, $factory);
}

public function it_is_initializable()
public function it_is_initializable(): void
{
$this->shouldHaveType(Client::class);
}

public function it_search_for_packages(HttpClient $client, Factory $factory, Response $response)
public function it_search_for_packages(HttpClient $client, Factory $factory, Response $response, Stream $body): void
{
$data = file_get_contents('spec/Packagist/Api/Fixture/search.json');
$response->getBody()->shouldBeCalled()->willReturn($data);
$response->getBody()->shouldBeCalled()->willReturn($body);
$body->getContents()->shouldBeCalled()->willReturn($data);

$client->request('GET', 'https://packagist.org/search.json?q=sylius')
->shouldBeCalled()
Expand All @@ -35,21 +37,23 @@ public function it_search_for_packages(HttpClient $client, Factory $factory, Res
$this->search('sylius');
}

public function it_search_for_packages_with_limit(HttpClient $client, Factory $factory, Response $response)
public function it_search_for_packages_with_limit(HttpClient $client, Factory $factory, Response $response, Stream $body): void
{
$data = file_get_contents('spec/Packagist/Api/Fixture/search.json');
$response->getBody()->shouldBeCalled()->willReturn($data);
$response->getBody()->shouldBeCalled()->willReturn($body);
$body->getContents()->shouldBeCalled()->willReturn($data);

$client->request('GET', 'https://packagist.org/search.json?q=sylius')->shouldBeCalled()->willReturn($response);
$factory->create(json_decode($data, true))->shouldBeCalled()->willReturn(array());

$this->search('sylius', [], 2);
}

public function it_searches_for_packages_with_filters(HttpClient $client, Factory $factory, Response $response)
public function it_searches_for_packages_with_filters(HttpClient $client, Factory $factory, Response $response, Stream $body): void
{
$data = file_get_contents('spec/Packagist/Api/Fixture/search.json');
$response->getBody()->shouldBeCalled()->willReturn($data);
$response->getBody()->shouldBeCalled()->willReturn($body);
$body->getContents()->shouldBeCalled()->willReturn($data);

$client->request('GET', 'https://packagist.org/search.json?tag=storage&q=sylius')
->shouldBeCalled()
Expand All @@ -60,10 +64,11 @@ public function it_searches_for_packages_with_filters(HttpClient $client, Factor
$this->search('sylius', ['tag' => 'storage']);
}

public function it_gets_popular_packages(HttpClient $client, Factory $factory, Response $response)
public function it_gets_popular_packages(HttpClient $client, Factory $factory, Response $response, Stream $body): void
{
$data = file_get_contents('spec/Packagist/Api/Fixture/popular.json');
$response->getBody()->shouldBeCalled()->willReturn($data);
$response->getBody()->shouldBeCalled()->willReturn($body);
$body->getContents()->shouldBeCalled()->willReturn($data);

$client->request('GET', 'https://packagist.org/explore/popular.json?page=1')
->shouldBeCalled()
Expand All @@ -76,10 +81,11 @@ public function it_gets_popular_packages(HttpClient $client, Factory $factory, R
$this->popular(2)->shouldHaveCount(2);
}

public function it_gets_package_details(HttpClient $client, Factory $factory, Response $response)
public function it_gets_package_details(HttpClient $client, Factory $factory, Response $response, Stream $body): void
{
$data = file_get_contents('spec/Packagist/Api/Fixture/get.json');
$response->getBody()->shouldBeCalled()->willReturn($data);
$response->getBody()->shouldBeCalled()->willReturn($body);
$body->getContents()->shouldBeCalled()->willReturn($data);

$client->request('GET', 'https://packagist.org/packages/sylius/sylius.json')
->shouldBeCalled()
Expand All @@ -90,10 +96,11 @@ public function it_gets_package_details(HttpClient $client, Factory $factory, Re
$this->get('sylius/sylius');
}

public function it_gets_composer_package_details(HttpClient $client, Factory $factory, Response $response)
public function it_gets_composer_package_details(HttpClient $client, Factory $factory, Response $response, Stream $body): void
{
$data = file_get_contents('spec/Packagist/Api/Fixture/get_composer.json');
$response->getBody()->shouldBeCalled()->willReturn($data);
$response->getBody()->shouldBeCalled()->willReturn($body);
$body->getContents()->shouldBeCalled()->willReturn($data);

$client->request('GET', 'https://packagist.org/p/sylius/sylius.json')
->shouldBeCalled()
Expand All @@ -104,10 +111,26 @@ public function it_gets_composer_package_details(HttpClient $client, Factory $fa
$this->getComposer('sylius/sylius');
}

public function it_lists_all_package_names(HttpClient $client, Factory $factory, Response $response)
public function it_gets_composer_lite_package_details(HttpClient $client, Factory $factory, Response $response, Stream $body): void
{
$data = file_get_contents('spec/Packagist/Api/Fixture/get_composer_lite.json');
$response->getBody()->shouldBeCalled()->willReturn($body);
$body->getContents()->shouldBeCalled()->willReturn($data);

$client->request('GET', 'https://packagist.org/p/sylius/sylius.json')
->shouldBeCalled()
->willReturn($response);

$factory->create(json_decode($data, true))->shouldBeCalled();

$this->getComposerLite('sylius/sylius');
}

public function it_lists_all_package_names(HttpClient $client, Factory $factory, Response $response, Stream $body): void
{
$data = file_get_contents('spec/Packagist/Api/Fixture/all.json');
$response->getBody()->shouldBeCalled()->willReturn($data);
$response->getBody()->shouldBeCalled()->willReturn($body);
$body->getContents()->shouldBeCalled()->willReturn($data);

$client->request('GET', 'https://packagist.org/packages/list.json')
->shouldBeCalled()
Expand All @@ -118,10 +141,11 @@ public function it_lists_all_package_names(HttpClient $client, Factory $factory,
$this->all();
}

public function it_filters_package_names_by_type(HttpClient $client, Factory $factory, Response $response)
public function it_filters_package_names_by_type(HttpClient $client, Factory $factory, Response $response, Stream $body): void
{
$data = file_get_contents('spec/Packagist/Api/Fixture/all.json');
$response->getBody()->shouldBeCalled()->willReturn($data);
$response->getBody()->shouldBeCalled()->willReturn($body);
$body->getContents()->shouldBeCalled()->willReturn($data);

$client->request('GET', 'https://packagist.org/packages/list.json?type=library')
->shouldBeCalled()
Expand All @@ -132,10 +156,11 @@ public function it_filters_package_names_by_type(HttpClient $client, Factory $fa
$this->all(['type' => 'library']);
}

public function it_filters_package_names_by_vendor(HttpClient $client, Factory $factory, Response $response)
public function it_filters_package_names_by_vendor(HttpClient $client, Factory $factory, Response $response, Stream $body): void
{
$data = file_get_contents('spec/Packagist/Api/Fixture/all.json');
$response->getBody()->shouldBeCalled()->willReturn($data);
$response->getBody()->shouldBeCalled()->willReturn($body);
$body->getContents()->shouldBeCalled()->willReturn($data);

$client->request('GET', 'https://packagist.org/packages/list.json?vendor=sylius')
->shouldBeCalled()
Expand All @@ -145,4 +170,5 @@ public function it_filters_package_names_by_vendor(HttpClient $client, Factory $

$this->all(['vendor' => 'sylius']);
}

}
2 changes: 1 addition & 1 deletion spec/Packagist/Api/Fixture/get_composer.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions spec/Packagist/Api/Fixture/get_composer_lite.json

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions spec/Packagist/Api/Result/FactorySpec.php
Expand Up @@ -63,6 +63,22 @@ public function it_creates_composer_packages()
}
}

public function it_creates_composer_lite_packages(): void
{
$data = json_decode(file_get_contents('spec/Packagist/Api/Fixture/get_composer_lite.json'), true);

$results = $this->create($data);
$results->shouldHaveCount(1);
$results->shouldBeArray();
foreach ($results as $result) {
$result->shouldBeAnInstanceOf('Packagist\Api\Result\Package');

foreach ($result->getVersions() as $version) {
$version->shouldBeAnInstanceOf('Packagist\Api\Result\Version');
}
}
}

public function it_creates_package_names()
{
$data = json_decode(file_get_contents('spec/Packagist/Api/Fixture/all.json'), true);
Expand Down Expand Up @@ -115,4 +131,5 @@ public function getMatchers(): array
}
);
}

}
48 changes: 28 additions & 20 deletions src/Packagist/Api/Client.php
Expand Up @@ -6,6 +6,7 @@

use GuzzleHttp\Client as HttpClient;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\GuzzleException;
use Packagist\Api\Result\Factory;
use Packagist\Api\Result\Package;
use Psr\Http\Message\StreamInterface;
Expand Down Expand Up @@ -55,9 +56,9 @@ public function __construct(
* * type: type of package (type in composer.json)
* * tags: tags of package (keywords in composer.json)
*
* @param string $query Name of package
* @param array $filters An array of filters
* @param int $limit Pages to limit results (0 = all pages)
* @param string $query Name of package
* @param array $filters An array of filters
* @param int $limit Pages to limit results (0 = all pages)
*
* @return array The results
*/
Expand Down Expand Up @@ -98,23 +99,25 @@ public function get(string $package)
}

/**
* Similar to {@link get()}, but uses composer metadata which is Packagist's preferred
* way of retrieving details, since responses are cached efficiently as static files
* by the Packagist service. The response lacks some metadata that is provided
* by {@link get()}, see https://packagist.org/apidoc for details.
*
* Caution: Returns an array of packages, you need to select the correct one
* from the indexed array.
*
* @since 1.6
*
* @see https://packagist.org/apidoc#get-package-data
* Contains tagged releases and dev versions
* @param string $package Full qualified name ex : myname/mypackage
*
* @return \Packagist\Api\Result\Package[] An array of packages, including the requested one.
* @return Package[] An array of packages, including the requested one.
*/
public function getComposer(string $package): array
{
return $this->respond(sprintf($this->url('/p2/%s~dev.json'), $package));
}

/**
* @see https://packagist.org/apidoc#get-package-data
* Contains only tagged releases
* @param string $package Full qualified name ex : myname/mypackage
* @return Package[] An array of packages, including the requested one.
*/
public function getComposer($package)
public function getComposerLite(string $package): array
{
return $this->respond(sprintf($this->url('/p/%s.json'), $package));
return $this->respond(sprintf($this->url('/p2/%s.json'), $package));
}

/**
Expand Down Expand Up @@ -197,9 +200,14 @@ protected function respond(string $url)
*/
protected function request(string $url): string
{
return (string) $this->httpClient
->request('GET', $url)
->getBody();
try {
return $this->httpClient
->request('GET', $url)
->getBody()
->getContents();
} catch (GuzzleException $e) {
return json_encode([]);
}
}

/**
Expand Down
40 changes: 40 additions & 0 deletions src/Packagist/Api/Result/Factory.php
Expand Up @@ -38,6 +38,10 @@ public function create(array $data)
// Used for /explore/popular.json
return $this->createSearchResults($data['packages']);
}
if (isset($data['minified']) && 'composer/2.0' === $data['minified']) {
// Used for /p2/<package>.json
return $this->createComposer2PackagesResults($data['packages']);
}
// Used for /p/<package>.json
return $this->createComposerPackagesResults($data['packages']);
}
Expand Down Expand Up @@ -127,6 +131,19 @@ public function createPackageResults(array $package): Package
$version['name'] ??= '';
$version['type'] ??= '';

if (isset($version['conflict']) && !is_array($version['conflict'])) {
unset($version['conflict']);
}
if (isset($version['suggest']) && !is_array($version['suggest'])) {
unset($version['suggest']);
}
if (isset($version['replace']) && !is_array($version['replace'])) {
unset($version['replace']);
}
if (isset($version['provide']) && !is_array($version['provide'])) {
unset($version['provide']);
}

if (isset($version['authors']) && $version['authors']) {
foreach ($version['authors'] as $key => $author) {
// Cast some potentially null properties to empty strings
Expand Down Expand Up @@ -171,4 +188,27 @@ protected function createResult(string $class, array $data): AbstractResult

return $result;
}

/**
* @param array $packages
* @return Package[]
*/
public function createComposer2PackagesResults(array $packages): array
{
$created = [];

foreach ($packages as $name => $package) {
// Create an empty package, only contains versions
$createdPackage = array(
'versions' => [],
);
foreach ($package as $version) {
$createdPackage['versions'][$version['version']] = $version;
}

$created[$name] = $this->createPackageResults($createdPackage);
}

return $created;
}
}

0 comments on commit 179847d

Please sign in to comment.