Skip to content

Commit 756c0f8

Browse files
committed
feat(repository): add RepositoryFactory interface to improve extensibility
1 parent 2107a52 commit 756c0f8

File tree

16 files changed

+368
-85
lines changed

16 files changed

+368
-85
lines changed

src/Bootstrap.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
use Internal\DLoad\Module\Common\Internal\ObjectContainer;
1010
use Internal\DLoad\Module\Common\OperatingSystem;
1111
use Internal\DLoad\Module\Common\Stability;
12+
use Internal\DLoad\Module\Repository\Internal\GitHub\Factory as GithubRepositoryFactory;
13+
use Internal\DLoad\Module\Repository\RepositoryProvider;
1214
use Internal\DLoad\Service\Container;
1315

1416
/**
@@ -93,6 +95,11 @@ public function withConfig(
9395
$this->container->bind(Architecture::class);
9496
$this->container->bind(OperatingSystem::class);
9597
$this->container->bind(Stability::class);
98+
$this->container->bind(
99+
RepositoryProvider::class,
100+
static fn(Container $container): RepositoryProvider => (new RepositoryProvider())
101+
->addRepositoryFactory($container->get(GithubRepositoryFactory::class)),
102+
);
96103

97104
return $this;
98105
}

src/Module/Downloader/Downloader.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
use Internal\DLoad\Module\Downloader\Task\DownloadTask;
1717
use Internal\DLoad\Module\Repository\AssetInterface;
1818
use Internal\DLoad\Module\Repository\ReleaseInterface;
19-
use Internal\DLoad\Module\Repository\RepositoryInterface;
19+
use Internal\DLoad\Module\Repository\Repository;
2020
use Internal\DLoad\Module\Repository\RepositoryProvider;
2121
use Internal\DLoad\Service\Destroyable;
2222
use Internal\DLoad\Service\Logger;
@@ -115,11 +115,11 @@ public function download(
115115
*
116116
* Fetches and filters releases from the repository based on stability and version constraints.
117117
*
118-
* @param RepositoryInterface $repository Repository to process
118+
* @param Repository $repository Repository to process
119119
* @param DownloadContext $context Download context information
120120
* @return \Closure(): ReleaseInterface Closure that returns the selected release
121121
*/
122-
private function processRepository(RepositoryInterface $repository, DownloadContext $context): \Closure
122+
private function processRepository(Repository $repository, DownloadContext $context): \Closure
123123
{
124124
return function () use ($repository, $context): ReleaseInterface {
125125
$this->logger->info(

src/Module/Repository/Collection/CompositeRepository.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Internal\DLoad\Module\Repository\Collection;
66

7-
use Internal\DLoad\Module\Repository\RepositoryInterface;
7+
use Internal\DLoad\Module\Repository\Repository;
88

99
/**
1010
* Collection of repositories that also implements the repository interface.
@@ -23,15 +23,15 @@
2323
* @internal
2424
* @psalm-internal Internal\DLoad\Module
2525
*/
26-
final class CompositeRepository implements RepositoryInterface
26+
final class CompositeRepository implements Repository
2727
{
2828
/**
29-
* @var array<RepositoryInterface>
29+
* @var array<Repository>
3030
*/
3131
private array $repositories;
3232

3333
/**
34-
* @param array<RepositoryInterface> $repositories List of repositories to include
34+
* @param array<Repository> $repositories List of repositories to include
3535
*/
3636
public function __construct(array $repositories)
3737
{

src/Module/Repository/Internal/GitHub/Factory.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,30 @@
44

55
namespace Internal\DLoad\Module\Repository\Internal\GitHub;
66

7+
use Internal\DLoad\Module\Common\Config\Embed\Repository as RepositoryConfig;
78
use Internal\DLoad\Module\Common\Config\GitHub as GitHubConfig;
9+
use Internal\DLoad\Module\Repository\RepositoryFactory;
810
use Symfony\Component\HttpClient\HttpClient;
911
use Symfony\Contracts\HttpClient\HttpClientInterface;
1012

1113
/**
1214
* @internal
1315
* @psalm-internal Internal\DLoad\Module\Repository
1416
*/
15-
final class Factory
17+
final class Factory implements RepositoryFactory
1618
{
1719
public function __construct(
1820
private readonly GitHubConfig $config,
1921
) {}
2022

21-
/**
22-
* @param non-empty-string $uri Package name in format "owner/repository" or full URL
23-
*/
24-
public function create(string $uri): GitHubRepository
23+
public function supports(RepositoryConfig $config): bool
2524
{
26-
$uri = \parse_url($uri, PHP_URL_PATH) ?? $uri;
25+
return \strtolower($config->type) === 'github';
26+
}
27+
28+
public function create(RepositoryConfig $config): GitHubRepository
29+
{
30+
$uri = \parse_url($config->uri, PHP_URL_PATH) ?? $config->uri;
2731
[$org, $repo] = \array_slice(\explode('/', $uri), -2);
2832

2933
return new GitHubRepository($org, $repo, $this->createClient());

src/Module/Repository/Internal/GitHub/GitHubRepository.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace Internal\DLoad\Module\Repository\Internal\GitHub;
66

77
use Internal\DLoad\Module\Repository\Collection\ReleasesCollection;
8-
use Internal\DLoad\Module\Repository\RepositoryInterface;
8+
use Internal\DLoad\Module\Repository\Repository;
99
use Internal\DLoad\Service\Destroyable;
1010
use Symfony\Component\HttpClient\HttpClient;
1111
use Symfony\Contracts\HttpClient\Exception\ExceptionInterface;
@@ -18,7 +18,7 @@
1818
* @internal
1919
* @psalm-internal Internal\DLoad\Module\Repository\GitHub
2020
*/
21-
final class GitHubRepository implements RepositoryInterface, Destroyable
21+
final class GitHubRepository implements Repository, Destroyable
2222
{
2323
private const URL_RELEASES = 'https://api.github.com/repos/%s/releases';
2424

src/Module/Repository/Internal/Release.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use Internal\DLoad\Module\Common\Stability;
1010
use Internal\DLoad\Module\Repository\Collection\AssetsCollection;
1111
use Internal\DLoad\Module\Repository\ReleaseInterface;
12-
use Internal\DLoad\Module\Repository\RepositoryInterface;
12+
use Internal\DLoad\Module\Repository\Repository;
1313

1414
/**
1515
* @internal
@@ -32,7 +32,7 @@ abstract class Release implements ReleaseInterface
3232
* @param non-empty-string $version
3333
*/
3434
public function __construct(
35-
protected RepositoryInterface $repository,
35+
protected Repository $repository,
3636
string $name,
3737
protected string $version,
3838
?Stability $stability = null,
@@ -43,7 +43,7 @@ public function __construct(
4343
$this->stability = $stability ?? $this->parseStability($version);
4444
}
4545

46-
public function getRepository(): RepositoryInterface
46+
public function getRepository(): Repository
4747
{
4848
return $this->repository;
4949
}

src/Module/Repository/ReleaseInterface.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ interface ReleaseInterface
2929
/**
3030
* Returns the repository this release belongs to.
3131
*
32-
* @return RepositoryInterface The parent repository
32+
* @return Repository The parent repository
3333
*/
34-
public function getRepository(): RepositoryInterface;
34+
public function getRepository(): Repository;
3535

3636
/**
3737
* Returns Composer's compatible "pretty" release version.

src/Module/Repository/RepositoryInterface.php renamed to src/Module/Repository/Repository.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* $filteredReleases = $releases->satisfies('^2.0.0')->sortByVersion();
1919
* ```
2020
*/
21-
interface RepositoryInterface
21+
interface Repository
2222
{
2323
/**
2424
* Returns the unique identifier of the repository.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Internal\DLoad\Module\Repository;
6+
7+
use Internal\DLoad\Module\Common\Config\Embed\Repository as RepositoryConfig;
8+
9+
/**
10+
* Interface for repository factory implementations.
11+
*
12+
* Each repository type (GitHub, GitLab, etc.) should have its own factory
13+
* implementation that creates repository instances from configuration.
14+
*/
15+
interface RepositoryFactory
16+
{
17+
/**
18+
* Determines if this factory can create a repository for the given config.
19+
*/
20+
public function supports(RepositoryConfig $config): bool;
21+
22+
/**
23+
* Creates a repository instance from the given config.
24+
*
25+
* @param RepositoryConfig $config Repository configuration
26+
* @return Repository Created repository instance
27+
* @throws \RuntimeException If repository cannot be created
28+
*/
29+
public function create(RepositoryConfig $config): Repository;
30+
}

src/Module/Repository/RepositoryProvider.php

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@
44

55
namespace Internal\DLoad\Module\Repository;
66

7-
use Internal\DLoad\Module\Common\Config\Embed\Repository;
8-
use Internal\DLoad\Module\Repository\Internal\GitHub\Factory as GithubFactory;
7+
use Internal\DLoad\Module\Common\Config\Embed\Repository as RepositoryConfig;
98

109
/**
1110
* Factory service for creating repository instances from configuration.
1211
*
13-
* Handles the creation of appropriate repository implementations based on
14-
* the repository type specified in the configuration.
12+
* Uses registered repository factories to create appropriate repository
13+
* implementations based on the repository type.
1514
*
1615
* ```php
1716
* // Get the RepositoryProvider service
@@ -26,25 +25,33 @@
2625
*/
2726
final class RepositoryProvider
2827
{
28+
/** @var RepositoryFactory[] $factories */
29+
private array $factories = [];
30+
2931
/**
30-
* @param GithubFactory $githubFactory Factory for creating GitHub repository instances
32+
* Adds a repository factory to the provider.
3133
*/
32-
public function __construct(
33-
private readonly GithubFactory $githubFactory,
34-
) {}
34+
public function addRepositoryFactory(RepositoryFactory $factory): self
35+
{
36+
$this->factories[] = $factory;
37+
return $this;
38+
}
3539

3640
/**
3741
* Creates a repository instance based on the provided configuration.
3842
*
39-
* @param Repository $config Repository configuration
40-
* @return RepositoryInterface Created repository instance
41-
* @throws \RuntimeException When an unknown repository type is specified
43+
* @param RepositoryConfig $config Repository configuration
44+
* @return Repository Created repository instance
45+
* @throws \RuntimeException When no factory supports the repository type
4246
*/
43-
public function getByConfig(Repository $config): RepositoryInterface
47+
public function getByConfig(RepositoryConfig $config): Repository
4448
{
45-
return match (\strtolower($config->type)) {
46-
'github' => $this->githubFactory->create($config->uri),
47-
default => throw new \RuntimeException("Unknown repository type `$config->type`."),
48-
};
49+
foreach ($this->factories as $factory) {
50+
if ($factory->supports($config)) {
51+
return $factory->create($config);
52+
}
53+
}
54+
55+
throw new \RuntimeException("No factory found for repository type `$config->type`.");
4956
}
5057
}

0 commit comments

Comments
 (0)