Skip to content

Commit bcf7de1

Browse files
committed
Add package link pages for dependents and suggesters
1 parent fa6dc7f commit bcf7de1

10 files changed

Lines changed: 187 additions & 56 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: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<div class="d-grid gap-3">
2+
{% for package in packages %}
3+
<div class="card">
4+
<div class="card-body py-2">
5+
{% set packageInfoUrl = dashboard_path('dashboard_packages_info', {packageName: package.name}) %}
6+
<a href="{{ packageInfoUrl }}"><h5 class="card-title">{{ package.name }}</h5></a>
7+
{% if package.mirrorRegistry %}
8+
<p class="card-text mb-1 text-body-secondary">Mirrored from {{ package.mirrorRegistry.name }}</p>
9+
{% endif %}
10+
<p class="card-text">{{ package.description ?? '<em>No description provided.</em>' }}</p>
11+
</div>
12+
</div>
13+
{% else %}
14+
<table class="table datagrid datagrid-empty">
15+
<tbody>
16+
{% for i in 1..14 %}
17+
<tr class="empty-row">
18+
<td><span></span></td>
19+
<td><span></span></td>
20+
<td><span></span></td>
21+
<td><span></span></td>
22+
<td><span></span></td>
23+
<td><span></span></td>
24+
</tr>
25+
26+
{% if 3 == loop.index %}
27+
<tr class="no-results">
28+
<td colspan="100">
29+
{{ t('datagrid.no_results', ea.i18n.translationParameters, 'EasyAdminBundle')|trans }}
30+
</td>
31+
</tr>
32+
{% endif %}
33+
{% endfor %}
34+
</tbody>
35+
</table>
36+
{% endfor %}
37+
</div>
38+
39+
{% if packages|length %}
40+
<div class="content-panel-footer without-padding without-border">
41+
{% block paginator %}
42+
{{ include(ea.templatePath('crud/paginator')) }}
43+
{% endblock paginator %}
44+
</div>
45+
{% endif %}

templates/dashboard/packages/list.html.twig

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -25,49 +25,5 @@
2525
{% endblock %}
2626

2727
{% block page_content %}
28-
<div class="d-grid gap-3">
29-
{% for package in packages %}
30-
<div class="card">
31-
<div class="card-body py-2">
32-
{% set packageInfoUrl = dashboard_path('dashboard_packages_info', {packageName: package.name}) %}
33-
<a href="{{ packageInfoUrl }}"><h5 class="card-title">{{ package.name }}</h5></a>
34-
{% if package.mirrorRegistry %}
35-
<p class="card-text mb-1 text-body-secondary">Mirrored from {{ package.mirrorRegistry.name }}</p>
36-
{% endif %}
37-
<p class="card-text">{{ package.description ?? '<em>No description provided.</em>' }}</p>
38-
</div>
39-
</div>
40-
{% else %}
41-
<table class="table datagrid datagrid-empty">
42-
<tbody>
43-
{% for i in 1..14 %}
44-
<tr class="empty-row">
45-
<td><span></span></td>
46-
<td><span></span></td>
47-
<td><span></span></td>
48-
<td><span></span></td>
49-
<td><span></span></td>
50-
<td><span></span></td>
51-
</tr>
52-
53-
{% if 3 == loop.index %}
54-
<tr class="no-results">
55-
<td colspan="100">
56-
{{ t('datagrid.no_results', ea.i18n.translationParameters, 'EasyAdminBundle')|trans }}
57-
</td>
58-
</tr>
59-
{% endif %}
60-
{% endfor %}
61-
</tbody>
62-
</table>
63-
{% endfor %}
64-
</div>
65-
66-
{% if packages|length %}
67-
<div class="content-panel-footer without-padding without-border">
68-
{% block paginator %}
69-
{{ include(ea.templatePath('crud/paginator')) }}
70-
{% endblock paginator %}
71-
</div>
72-
{% endif %}
28+
{% include 'dashboard/packages/_package_list.html.twig' %}
7329
{% endblock %}
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: 10 additions & 6 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 %}
@@ -83,10 +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>
93+
<li>{{ link.linkedPackageName }}: {{ link.linkedVersionConstraint }}</li>
9094
{% endif %}
9195
{% else %}
9296
<li>None</li>
@@ -101,10 +105,10 @@
101105

102106
<ul>
103107
{% 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>
108+
{% if link.linkedPackageName is existing_package %}
109+
<li><a href="{{ dashboard_path('dashboard_packages_info', {packageName: link.linkedPackageName}) }}">{{ link.linkedPackageName }}</a>: {{ link.linkedVersionConstraint }}</li>
106110
{% else %}
107-
<li>{{ link.packageName }}: {{ link.packageVersion }}</li>
111+
<li>{{ link.linkedPackageName }}: {{ link.linkedVersionConstraint }}</li>
108112
{% endif %}
109113
{% else %}
110114
<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/DashboardPackagesControllerTest.php

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

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

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

1012
class DashboardPackagesControllerTest extends WebTestCase
1113
{
1214
use WebTestCaseTrait;
1315

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