built a base to work from

master
Tim Bazuin 5 years ago
parent 4613cb69ea
commit 8d1b25e8ce

@ -1,3 +1,13 @@
# php-gitlab-api-async
An asynchronous implementation of the Gitlab API in PHP, using asynchronous requests/promises to do all of it's I/O.
An asynchronous implementation of the Gitlab API in PHP, using asynchronous requests/promises to do all of it's I/O.
- Make pagination not matter
- Fix a way to do token auth that doesn't suck
Use cases:
- Check if group exists
- Create group
- Check if project exists
- Create project
- Find all projects in group and subgroups

@ -0,0 +1,24 @@
{
"name": "cijber/php-gitlab-api-async",
"description": "An asynchronous implementation of the Gitlab API in PHP, using asynchronous requests/promises to do all of its I/O.",
"type": "library",
"require-dev": {
"react/http-client": "^0.5.9",
"php-http/react-adapter": "^2.3",
"php-http/mock-client": "^1.3",
"phpunit/phpunit": "^8.3"
},
"license": "GPL 3.0",
"require": {
"php-http/async-client-implementation": "^1.0",
"php": "^7.3",
"symfony/options-resolver": "^4.3",
"ext-json": "*"
},
"autoload": {
"psr-4": { "Gitlab\\": "lib/Gitlab/" }
},
"autoload-dev": {
"psr-4": { "Gitlab\\Tests\\": "test/Gitlab/Tests/" }
}
}

2637
composer.lock generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,81 @@
<?php
namespace Gitlab\Api;
use Gitlab\Http\QueryString;
use Http\Client\HttpAsyncClient;
use Http\Message\MessageFactory;
use Http\Promise\Promise;
use Symfony\Component\OptionsResolver\OptionsResolver;
abstract class Base
{
private $client;
private $messageFactory;
public function __construct(
HttpAsyncClient $client,
MessageFactory $messageFactory
)
{
$this->client = $client;
$this->messageFactory = $messageFactory;
}
protected function getClient() : HttpAsyncClient
{
return $this->client;
}
protected function createOptionsResolver() : OptionsResolver
{
$resolver = new OptionsResolver();
// Every query can have page and per_page
$resolver->setDefined('page')
->setAllowedTypes('page', 'int')
->setAllowedValues('page', function ($value) {
return $value > 0;
})
->setDefined('per_page')
->setAllowedTypes('per_page', 'int')
->setAllowedValues('per_page', function ($value) {
return $value > 0 && $value <= 100;
});
return $resolver;
}
protected function getBooleanNormaliser() : callable
{
return function ($value) {
return $value === true ? 'true' : 'false';
};
}
protected function encodeObjectPath(string $path) : string
{
return str_replace('.', '%2E', rawurlencode($path));
}
/**
* @param string $path
* @param array $parameters
* @return Promise
* @throws \Exception
*/
protected function post(string $path, array $parameters) : Promise
{
$uri = $path;
$request = $this->messageFactory->createRequest(
'POST',
$uri,
[],
QueryString::build($parameters));
return $this->getClient()->sendAsyncRequest($request);
}
}

@ -0,0 +1,39 @@
<?php
namespace Gitlab\Api;
use Gitlab\Api\Plugin\Authentication;
use Http\Client\Common\Plugin\AddHostPlugin;
use Http\Client\Common\Plugin\AddPathPlugin;
use Http\Client\Common\PluginClient;
use Http\Client\HttpAsyncClient;
use Http\Discovery\UriFactoryDiscovery;
use Http\Message\UriFactory;
class ClientFactory
{
public static function create(
HttpAsyncClient $client,
Authentication $authentication,
string $host
) : PluginClient
{
/**
* @var UriFactory
*/
$uriFactory = UriFactoryDiscovery::find();
$plugins = [
$authentication,
// Prepend api version to path
new AddPathPlugin($uriFactory->createUri('/api/v4/')),
// Make sure host is set to the right uri
new AddHostPlugin($uriFactory->createUri($host), ['replace' => true]),
];
return new PluginClient($client, $plugins);
}
}

@ -0,0 +1,25 @@
<?php
namespace Gitlab\Api;
use Http\Promise\Promise;
class Group extends Base
{
public function projects(string $path, array $parameters) : Promise
{
$resolver = $this->createOptionsResolver();
$resolver->setDefined('include_subgroups')
->setAllowedTypes('include_subgroups', 'bool')
->setNormalizer('include_subgroups', $this->getBooleanNormaliser());
$queryPath = 'groups/' . $this->encodeObjectPath($path) . '/projects';
$resolvedParameters = $resolver->resolve($parameters);
return $this->post($queryPath, $resolvedParameters);
}
}

@ -0,0 +1,26 @@
<?php
namespace Gitlab\Api\Parameters;
class ListGroupProjects
{
/*
* @var bool
*/
private $archived;// boolean no Limit by archived status
private $visibility;// string no Limit by visibility public, internal, or private
private $order_by;// string no Return projects ordered by id, name, path, created_at, updated_at, or last_activity_at fields. Default is created_at
private $sort;// string no Return projects sorted in asc or desc order. Default is desc
private $search;// string no Return list of authorized projects matching the search criteria
private $simple;// boolean no Return only the ID, URL, name, and path of each project
private $owned;// boolean no Limit by projects owned by the current user
private $starred;// boolean no Limit by projects starred by the current user
private $with_issues_enabled;// boolean no Limit by projects with issues feature enabled. Default is false
private $with_merge_requests_enabled;// boolean no Limit by projects with merge requests feature enabled. Default is false
private $with_shared;// boolean no Include projects shared to this group. Default is true
private $include_subgroups;// boolean no Include projects in subgroups of this group. Default is false
private $with_custom_attributes;// boolean no Include custom attributes in response (admins only)
}

@ -0,0 +1,63 @@
<?php
namespace Gitlab\Api\Plugin;
use Http\Client\Common\Plugin;
use Http\Promise\Promise;
use Psr\Http\Message\RequestInterface;
class Authentication implements Plugin
{
public const TOKEN = 'token';
public const OAUTH = 'oauth';
private $method;
private $token;
private $sudo;
public function __construct(
string $method,
string $token,
bool $sudo = false
)
{
if ($method !== self::TOKEN && $method !== self::OAUTH) {
throw new \InvalidArgumentException('Method must be either TOKEN or OAUTH');
}
$this->method = $method;
$this->token = $token;
$this->sudo = $sudo;
}
/**
* Handle the request and return the response coming from the next callable.
*
* @see http://docs.php-http.org/en/latest/plugins/build-your-own.html
*
* @param RequestInterface $request
* @param callable $next Next middleware in the chain, the request is passed as the first argument
* @param callable $first First middleware in the chain, used to to restart a request
*
* @return Promise Resolves a PSR-7 Response or fails with an Http\Client\Exception (The same as HttpAsyncClient).
*/
public function handleRequest(RequestInterface $request, callable $next, callable $first)
{
if ($this->sudo === true) {
$request = $request->withAddedHeader('Sudo', 'yes');
}
switch ($this->method) {
case self::TOKEN:
$request = $request->withAddedHeader('Private-Token', $this->token);
break;
case self::OAUTH:
$request = $request->withAddedHeader('Authorization', 'Bearer ' . $this->token);
break;
}
return $next($request);
}
}

@ -0,0 +1,11 @@
<?php
namespace Gitlab\Api;
class Project extends Base
{
}

@ -0,0 +1,15 @@
<?php
namespace Gitlab\Api\Response;
class PaginationPromiseResolve
{
public function __construct(
)
{
}
}

@ -0,0 +1,13 @@
<?php
namespace Gitlab\Http;
final class QueryString
{
public static function build($values) : string
{
return json_encode($values);
}
}
Loading…
Cancel
Save