Skip to content

Commit 9d5555b

Browse files
committed
Add package link pages for dependents and suggesters
1 parent 82c020d commit 9d5555b

8 files changed

Lines changed: 139 additions & 27 deletions

File tree

src/Controller/Dashboard/DashboardPackagesInfoController.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,27 @@
33
namespace CodedMonkey\Dirigent\Controller\Dashboard;
44

55
use CodedMonkey\Dirigent\Attribute\IsGrantedAccess;
6+
use CodedMonkey\Dirigent\Doctrine\Entity\Dependent;
67
use CodedMonkey\Dirigent\Doctrine\Entity\Package;
8+
use CodedMonkey\Dirigent\Doctrine\Entity\Provider;
9+
use CodedMonkey\Dirigent\Doctrine\Entity\Suggester;
710
use CodedMonkey\Dirigent\Doctrine\Repository\PackageRepository;
11+
use CodedMonkey\Dirigent\EasyAdmin\PackagePaginator;
812
use Composer\Semver\VersionParser;
13+
use Doctrine\ORM\EntityManagerInterface;
14+
use EasyCorp\Bundle\EasyAdminBundle\Dto\PaginatorDto;
15+
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
916
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
17+
use Symfony\Component\HttpFoundation\Request;
1018
use Symfony\Component\HttpFoundation\Response;
1119
use Symfony\Component\Routing\Attribute\Route;
1220

1321
class DashboardPackagesInfoController extends AbstractController
1422
{
1523
public function __construct(
24+
private readonly EntityManagerInterface $entityManager,
1625
private readonly PackageRepository $packageRepository,
26+
private readonly AdminUrlGenerator $adminUrlGenerator,
1727
) {
1828
}
1929

@@ -34,10 +44,16 @@ public function info(string $packageName, ?string $packageVersion = null): Respo
3444
$version = $package->getLatestVersion();
3545
}
3646

47+
$dependentCount = $this->entityManager->getRepository(Dependent::class)->count(['dependentPackageName' => $package->getName()]);
48+
$suggesterCount = $this->entityManager->getRepository(Suggester::class)->count(['suggestedPackageName' => $package->getName()]);
49+
3750
return $this->render('dashboard/packages/package_info.html.twig', [
3851
'package' => $package,
3952
'latestVersion' => $latestVersion,
4053
'version' => $version,
54+
55+
'dependentCount' => $dependentCount,
56+
'suggesterCount' => $suggesterCount,
4157
]);
4258
}
4359

@@ -56,6 +72,58 @@ public function versions(string $packageName): Response
5672
]);
5773
}
5874

75+
#[Route('/dashboard/packages/dependents/{packageName}', name: 'dashboard_packages_dependents', requirements: ['packageName' => '[a-z0-9_.-]+/[a-z0-9_.-]+'])]
76+
#[IsGrantedAccess]
77+
public function dependents(Request $request, string $packageName): Response
78+
{
79+
$package = $this->packageRepository->findOneBy(['name' => $packageName]);
80+
81+
$dependentRepository = $this->entityManager->getRepository(Dependent::class);
82+
$queryBuilder = $dependentRepository->createQueryBuilder('dependent');
83+
$queryBuilder
84+
->leftJoin('dependent.package', 'package')
85+
->andWhere('dependent.dependentPackageName = :packageName')
86+
->setParameter('packageName', $package->getName())
87+
->addOrderBy('package.name', 'ASC');
88+
89+
$paginatorDto = new PaginatorDto(20, 3, 1, true, null);
90+
$paginatorDto->setPageNumber($request->query->getInt('page', 1));
91+
$paginator = (new PackagePaginator($this->adminUrlGenerator))->paginate($paginatorDto, $queryBuilder);
92+
$dependents = $paginator->getResults();
93+
94+
return $this->render('dashboard/packages/package_dependents.html.twig', [
95+
'package' => $package,
96+
'dependents' => $dependents,
97+
'paginator' => $paginator,
98+
]);
99+
}
100+
101+
#[Route('/dashboard/packages/suggesters/{packageName}', name: 'dashboard_packages_suggesters', requirements: ['packageName' => '[a-z0-9_.-]+/[a-z0-9_.-]+'])]
102+
#[IsGrantedAccess]
103+
public function suggesters(Request $request, string $packageName): Response
104+
{
105+
$package = $this->packageRepository->findOneBy(['name' => $packageName]);
106+
107+
$suggesterRepository = $this->entityManager->getRepository(Suggester::class);
108+
$queryBuilder = $suggesterRepository->createQueryBuilder('suggester');
109+
$queryBuilder
110+
->leftJoin('suggester.package', 'package')
111+
->andWhere('suggester.suggestedPackageName = :packageName')
112+
->setParameter('packageName', $package->getName())
113+
->addOrderBy('package.name', 'ASC');
114+
115+
$paginatorDto = new PaginatorDto(20, 3, 1, true, null);
116+
$paginatorDto->setPageNumber($request->query->getInt('page', 1));
117+
$paginator = (new PackagePaginator($this->adminUrlGenerator))->paginate($paginatorDto, $queryBuilder);
118+
$suggesters = $paginator->getResults();
119+
120+
return $this->render('dashboard/packages/package_suggesters.html.twig', [
121+
'package' => $package,
122+
'suggesters' => $suggesters,
123+
'paginator' => $paginator,
124+
]);
125+
}
126+
59127
#[Route('/dashboard/packages/statistics/{packageName}', name: 'dashboard_packages_statistics', requirements: ['packageName' => '[a-z0-9_.-]+/[a-z0-9_.-]+'])]
60128
#[IsGrantedAccess]
61129
public function statistics(string $packageName): Response

src/EasyAdmin/PackagePaginator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public function paginate(PaginatorDto $paginatorDto, QueryBuilder $queryBuilder)
4040
->setMaxResults($this->pageSize)
4141
->getQuery();
4242

43-
$paginator = new Paginator($query, $paginatorDto->fetchJoinCollection());
43+
$paginator = new Paginator($query, false);
4444

4545
$this->results = $paginator->getIterator();
4646
$this->numResults = $paginator->count();

templates/dashboard/packages/_package_header.html.twig

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
<a {% if currentPage == 'versions' %}class="nav-link active" aria-current="page"{% else %}class="nav-link text-primary"{% endif%} href="{{ packageVersionsUrl }}">{{ 'Versions'|trans }}</a>
1111
</li>
1212
<li class="nav-item">
13-
<span class="nav-link disabled">{{ 'Dependants'|trans }}</span>
13+
{% set packageDependentsUrl = dashboard_path('dashboard_packages_dependents', {packageName: package.name}) %}
14+
<a {% if currentPage == 'dependents' %}class="nav-link active" aria-current="page"{% else %}class="nav-link text-primary"{% endif%} href="{{ packageDependentsUrl }}">{{ 'Dependents'|trans }}</a>
1415
</li>
1516
<li class="nav-item">
16-
{% set packageVersionsUrl = dashboard_path('dashboard_packages_statistics', {packageName: package.name}) %}
17-
<a {% if currentPage == 'statistics' %}class="nav-link active" aria-current="page"{% else %}class="nav-link text-primary"{% endif%} href="{{ packageVersionsUrl }}">{{ 'Statistics'|trans }}</a>
17+
{% set packageStatisticsUrl = dashboard_path('dashboard_packages_statistics', {packageName: package.name}) %}
18+
<a {% if currentPage == 'statistics' %}class="nav-link active" aria-current="page"{% else %}class="nav-link text-primary"{% endif%} href="{{ packageStatisticsUrl }}">{{ 'Statistics'|trans }}</a>
1819
</li>
1920
</ul>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{% extends 'dashboard/packages/package_base.html.twig' %}
2+
3+
{% block page_title %}{{ package.name }} <small>{{ 'Dependents'|trans }}</small>{% endblock %}
4+
5+
{% block page_content %}
6+
{% include 'dashboard/packages/package_header.html.twig' with {currentPage: 'dependents'} %}
7+
8+
{% include 'dashboard/packages/_package_list.html.twig' with {packages: dependents|map(dependent => dependent.package)} %}
9+
{% endblock %}

templates/dashboard/packages/package_info.html.twig

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@
4545
<div><a href="{{ version.source.url }}">Source</a></div>
4646
{% endif %}
4747
<div>Installs: {{ package.installations.total }}</div>
48+
{% set packageDependentsUrl = dashboard_path('dashboard_packages_dependents', {packageName: package.name}) %}
49+
<div><a href="{{ packageDependentsUrl }}">{{ 'Dependents'|trans }}</a>: {{ dependentCount }}</div>
50+
{% set packageSuggestersUrl = dashboard_path('dashboard_packages_suggesters', {packageName: package.name}) %}
51+
<div><a href="{{ packageSuggestersUrl }}">{{ 'Suggesters'|trans }}</a>: {{ suggesterCount }}</div>
4852
{% if version.license %}
4953
<div>License: {{ version.license|join(', ') }}</div>
5054
{% else %}
@@ -65,7 +69,7 @@
6569
{{ _self.linkBlock("requires", version.require) }}
6670
{{ _self.linkBlock("requires (dev)", version.devRequire) }}
6771
{{ _self.linkBlock("provides", version.provide) }}
68-
{{ _self.suggestBlock("suggests", version.suggest) }}
72+
{{ _self.linkBlock("suggests", version.suggest) }}
6973
{{ _self.linkBlock("conflicts", version.conflict) }}
7074
{{ _self.linkBlock("replaces", version.replace) }}
7175
</div>
@@ -83,28 +87,10 @@
8387

8488
<ul>
8589
{% for link in links %}
86-
{% if link.packageName is existing_package %}
87-
<li><a href="{{ dashboard_path('dashboard_packages_info', {packageName: link.packageName}) }}">{{ link.packageName }}</a>: {{ link.packageVersion }}</li>
90+
{% if link.linkedPackageName is existing_package %}
91+
<li><a href="{{ dashboard_path('dashboard_packages_info', {packageName: link.linkedPackageName}) }}">{{ link.linkedPackageName }}</a>: {{ link.linkedVersionConstraint }}</li>
8892
{% else %}
89-
<li>{{ link.packageName }}: {{ link.packageVersion }}</li>
90-
{% endif %}
91-
{% else %}
92-
<li>None</li>
93-
{% endfor %}
94-
</ul>
95-
</div>
96-
{% endmacro %}
97-
98-
{% macro suggestBlock(title, links) %}
99-
<div class="col-md-6 col-lg-4">
100-
<div class="h5">{{ title }}</div>
101-
102-
<ul>
103-
{% for link in links %}
104-
{% if link.packageName is existing_package %}
105-
<li><a href="{{ dashboard_path('dashboard_packages_info', {packageName: link.packageName}) }}">{{ link.packageName }}</a>: {{ link.packageVersion }}</li>
106-
{% else %}
107-
<li>{{ link.packageName }}: {{ link.packageVersion }}</li>
93+
<li>{{ link.linkedPackageName }}: {{ link.linkedVersionConstraint }}</li>
10894
{% endif %}
10995
{% else %}
11096
<li>None</li>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{% extends 'dashboard/packages/package_base.html.twig' %}
2+
3+
{% block page_title %}{{ package.name }} <small>{{ 'Suggesters'|trans }}</small>{% endblock %}
4+
5+
{% block page_content %}
6+
{% include 'dashboard/packages/package_header.html.twig' %}
7+
8+
{% include 'dashboard/packages/_package_list.html.twig' with {packages: suggesters|map(suggester => suggester.package)} %}
9+
{% endblock %}

tests/FunctionalTests/Controller/Dashboard/DashboardPackagesInfoControllerTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,52 @@
22

33
namespace CodedMonkey\Dirigent\Tests\FunctionalTests\Controller\Dashboard;
44

5+
use CodedMonkey\Dirigent\Doctrine\Entity\User;
56
use CodedMonkey\Dirigent\Doctrine\Repository\PackageRepository;
7+
use CodedMonkey\Dirigent\Doctrine\Repository\UserRepository;
68
use CodedMonkey\Dirigent\Tests\FunctionalTests\WebTestCaseTrait;
79
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
810

911
class DashboardPackagesInfoControllerTest extends WebTestCase
1012
{
1113
use WebTestCaseTrait;
1214

15+
public function testDependents(): void
16+
{
17+
$client = static::createClient();
18+
19+
/** @var UserRepository $userRepository */
20+
$userRepository = $client->getContainer()->get(UserRepository::class);
21+
22+
/** @var User $user */
23+
$user = $userRepository->findOneByUsername('user');
24+
$client->loginUser($user);
25+
26+
$client->request('GET', '/?routeName=dashboard_packages_dependents&routeParams[packageName]=psr/log');
27+
28+
$this->assertResponseStatusCodeSame(200);
29+
30+
$this->assertAnySelectorTextSame('h1 small', 'Dependents');
31+
}
32+
33+
public function testSuggesters(): void
34+
{
35+
$client = static::createClient();
36+
37+
/** @var UserRepository $userRepository */
38+
$userRepository = $client->getContainer()->get(UserRepository::class);
39+
40+
/** @var User $user */
41+
$user = $userRepository->findOneByUsername('user');
42+
$client->loginUser($user);
43+
44+
$client->request('GET', '/?routeName=dashboard_packages_suggesters&routeParams[packageName]=psr/log');
45+
46+
$this->assertResponseStatusCodeSame(200);
47+
48+
$this->assertAnySelectorTextSame('h1 small', 'Suggesters');
49+
}
50+
1351
public function testStatistics(): void
1452
{
1553
$client = static::createClient();

translations/messages.en.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ Account: Account
22
Administration: Administration
33
Credits: Credits
44
Dashboard: Dashboard
5-
Dependants: Dependants
5+
Dependents: Dependents
66
Documentation: Documentation
77
Info: Info
88
Packages: Packages
99
Personal: Personal
1010
Sign out: Sign out
1111
Statistics: Statistics
12+
Suggesters: Suggesters
1213
Usage: Usage
1314

1415
Access token: Access token

0 commit comments

Comments
 (0)