Skip to content

Commit 7f66dbf

Browse files
committed
Add package link pages for dependents and suggesters
1 parent 4062b2d commit 7f66dbf

8 files changed

Lines changed: 135 additions & 28 deletions

File tree

src/Controller/Dashboard/DashboardPackagesInfoController.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,23 @@
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\Suggester;
79
use CodedMonkey\Dirigent\Doctrine\Repository\PackageRepository;
10+
use CodedMonkey\Dirigent\EasyAdmin\PackagePaginator;
811
use Composer\Semver\VersionParser;
12+
use Doctrine\ORM\EntityManagerInterface;
13+
use EasyCorp\Bundle\EasyAdminBundle\Dto\PaginatorDto;
914
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
15+
use Symfony\Component\HttpFoundation\Request;
1016
use Symfony\Component\HttpFoundation\Response;
1117
use Symfony\Component\Routing\Attribute\Route;
1218

1319
class DashboardPackagesInfoController extends AbstractController
1420
{
1521
public function __construct(
22+
private readonly EntityManagerInterface $entityManager,
1623
private readonly PackageRepository $packageRepository,
1724
) {
1825
}
@@ -34,10 +41,16 @@ public function info(string $packageName, ?string $packageVersion = null): Respo
3441
$version = $package->getLatestVersion();
3542
}
3643

44+
$dependentCount = $this->entityManager->getRepository(Dependent::class)->count(['dependentPackageName' => $package->getName()]);
45+
$suggesterCount = $this->entityManager->getRepository(Suggester::class)->count(['suggestedPackageName' => $package->getName()]);
46+
3747
return $this->render('dashboard/packages/package_info.html.twig', [
3848
'package' => $package,
3949
'latestVersion' => $latestVersion,
4050
'version' => $version,
51+
52+
'dependentCount' => $dependentCount,
53+
'suggesterCount' => $suggesterCount,
4154
]);
4255
}
4356

@@ -56,6 +69,54 @@ public function versions(string $packageName): Response
5669
]);
5770
}
5871

72+
#[Route('/dashboard/packages/dependents/{packageName}', name: 'dashboard_packages_dependents', requirements: ['packageName' => '[a-z0-9_.-]+/[a-z0-9_.-]+'])]
73+
#[IsGrantedAccess]
74+
public function dependents(Request $request, string $packageName): Response
75+
{
76+
$package = $this->packageRepository->findOneBy(['name' => $packageName]);
77+
78+
$dependentRepository = $this->entityManager->getRepository(Dependent::class);
79+
$queryBuilder = $dependentRepository->createQueryBuilder('dependent');
80+
$queryBuilder
81+
->leftJoin('dependent.package', 'package')
82+
->andWhere('dependent.dependentPackageName = :packageName')
83+
->setParameter('packageName', $package->getName())
84+
->addOrderBy('package.name', 'ASC');
85+
86+
$paginator = PackagePaginator::fromRequest($request, $queryBuilder, $this->container->get('router'));
87+
$dependents = $paginator->getResults();
88+
89+
return $this->render('dashboard/packages/package_dependents.html.twig', [
90+
'package' => $package,
91+
'dependents' => $dependents,
92+
'paginator' => $paginator,
93+
]);
94+
}
95+
96+
#[Route('/dashboard/packages/suggesters/{packageName}', name: 'dashboard_packages_suggesters', requirements: ['packageName' => '[a-z0-9_.-]+/[a-z0-9_.-]+'])]
97+
#[IsGrantedAccess]
98+
public function suggesters(Request $request, string $packageName): Response
99+
{
100+
$package = $this->packageRepository->findOneBy(['name' => $packageName]);
101+
102+
$suggesterRepository = $this->entityManager->getRepository(Suggester::class);
103+
$queryBuilder = $suggesterRepository->createQueryBuilder('suggester');
104+
$queryBuilder
105+
->leftJoin('suggester.package', 'package')
106+
->andWhere('suggester.suggestedPackageName = :packageName')
107+
->setParameter('packageName', $package->getName())
108+
->addOrderBy('package.name', 'ASC');
109+
110+
$paginator = PackagePaginator::fromRequest($request, $queryBuilder, $this->container->get('router'));
111+
$suggesters = $paginator->getResults();
112+
113+
return $this->render('dashboard/packages/package_suggesters.html.twig', [
114+
'package' => $package,
115+
'suggesters' => $suggesters,
116+
'paginator' => $paginator,
117+
]);
118+
}
119+
59120
#[Route('/dashboard/packages/statistics/{packageName}', name: 'dashboard_packages_statistics', requirements: ['packageName' => '[a-z0-9_.-]+/[a-z0-9_.-]+'])]
60121
#[IsGrantedAccess]
61122
public function statistics(string $packageName): Response

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 = 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 = 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 = 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>

templates/dashboard/packages/_package_list.html.twig

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
{% set packages = packages ?? paginator.results %}
2+
13
<div class="d-grid gap-3">
2-
{% for package in paginator.results %}
4+
{% for package in packages %}
35
<div class="card">
46
<div class="card-body py-2">
57
{% set packageInfoUrl = path('dashboard_packages_info', {packageName: package.name}) %}
@@ -36,7 +38,7 @@
3638
{% endfor %}
3739
</div>
3840

39-
{% if paginator.numResults|length %}
41+
{% if paginator.numResults > 0 %}
4042
<div class="content-panel-footer without-padding without-border">
4143
{% block paginator %}
4244
{{ include(ea.templatePath('crud/paginator')) }}
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', {packages: dependents|map(dependent => dependent.package), paginator: paginator}, with_context: false) }}
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 = path('dashboard_packages_dependents', {packageName: package.name}) %}
49+
<div><a href="{{ packageDependentsUrl }}">{{ 'Dependents'|trans }}</a>: {{ dependentCount }}</div>
50+
{% set packageSuggestersUrl = 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="{{ path('dashboard_packages_info', {packageName: link.packageName}) }}">{{ link.packageName }}</a>: {{ link.packageVersion }}</li>
90+
{% if link.linkedPackageName is existing_package %}
91+
<li><a href="{{ 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="{{ 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', {packages: suggesters|map(suggester => suggester.package), paginator: paginator}, with_context: false) }}
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)