Skip to content

Commit 4a3f401

Browse files
committed
use StreamedResponse in packages() controller method
1 parent 50fe808 commit 4a3f401

File tree

4 files changed

+64
-37
lines changed

4 files changed

+64
-37
lines changed

src/Controller/RepoController.php

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
1414
use Symfony\Component\HttpFoundation\JsonResponse;
1515
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\HttpFoundation\Response;
1617
use Symfony\Component\HttpFoundation\StreamedResponse;
1718
use Symfony\Component\HttpKernel\Exception\HttpException;
1819
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
1920
use Symfony\Component\Messenger\MessageBusInterface;
2021
use Symfony\Component\Routing\Annotation\Route;
2122
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
22-
use Symfony\Component\Routing\RouterInterface;
2323

2424
final class RepoController extends AbstractController
2525
{
@@ -41,32 +41,42 @@ public function __construct(
4141
* @Route("/packages.json", host="{organization}{sep1}repo{sep2}{domain}", name="repo_packages", methods={"GET"}, defaults={"domain":"%domain%","sep1"="%organization_separator%","sep2"="%domain_separator%"}, requirements={"domain"="%domain%","sep1"="%organization_separator%","sep2"="%domain_separator%"})
4242
* @Cache(public=false)
4343
*/
44-
public function packages(Request $request, Organization $organization): JsonResponse
44+
public function packages(Request $request, Organization $organization): Response
4545
{
4646
$packageNames = $this->packageQuery->getAllNames($organization->id());
47-
[$lastModified, $packages] = $this->packageManager->findProviders($organization->alias(), $packageNames);
48-
49-
$response = (new JsonResponse([
50-
'packages' => $packages,
51-
'available-packages' => array_map(static fn (PackageName $packageName) => $packageName->name(), $packageNames),
52-
'metadata-url' => '/p2/%package%.json',
53-
'notify-batch' => $this->generateUrl('repo_package_downloads', [
54-
'organization' => $organization->alias(),
55-
], UrlGeneratorInterface::ABSOLUTE_URL),
56-
'search' => 'https://packagist.org/search.json?q=%query%&type=%type%',
57-
'mirrors' => [
58-
[
59-
'dist-url' => $this->generateUrl(
60-
'organization_repo_url',
61-
['organization' => $organization->alias()],
62-
RouterInterface::ABSOLUTE_URL
63-
).'dists/%package%/%version%/%reference%.%type%',
64-
'preferred' => true,
47+
[$lastModified, $loader] = $this->packageManager->findProviders($organization->alias(), $packageNames);
48+
49+
$response = (new StreamedResponse(function () use ($organization, $packageNames, $loader): void {
50+
$outputStream = \fopen('php://output', 'wb');
51+
if (false === $outputStream) {
52+
throw new HttpException(500, 'Could not open output stream to send binary file.'); // @codeCoverageIgnore
53+
}
54+
55+
\fwrite($outputStream, ' ');
56+
\flush();
57+
\fwrite($outputStream, \json_encode([
58+
'packages' => $loader(),
59+
'available-packages' => array_map(static fn (PackageName $packageName) => $packageName->name(), $packageNames),
60+
'metadata-url' => '/p2/%package%.json',
61+
'providers-url' => '/p2/%package%.json',
62+
'notify-batch' => $this->generateUrl('repo_package_downloads', [
63+
'organization' => $organization->alias(),
64+
], UrlGeneratorInterface::ABSOLUTE_URL),
65+
'search' => 'https://packagist.org/search.json?q=%query%&type=%type%',
66+
'mirrors' => [
67+
[
68+
'dist-url' => $this->generateUrl(
69+
'organization_repo_url',
70+
['organization' => $organization->alias()],
71+
UrlGeneratorInterface::ABSOLUTE_URL
72+
).'dists/%package%/%version%/%reference%.%type%',
73+
'preferred' => true,
74+
],
6575
],
66-
],
67-
]))
68-
->setPrivate()
69-
->setLastModified($lastModified);
76+
], JsonResponse::DEFAULT_ENCODING_OPTIONS));
77+
}, Response::HTTP_OK, ['Content-Type' => 'application/json', 'X-Accel-Buffering' => 'no']))
78+
->setLastModified($lastModified)
79+
->setPrivate();
7080

7181
$response->isNotModified($request);
7282

@@ -149,18 +159,27 @@ public function downloads(Request $request, Organization $organization): JsonRes
149159
* requirements={"domain"="%domain%","package"="%package_name_pattern%","sep1"="%organization_separator%","sep2"="%domain_separator%"})
150160
* @Cache(public=false)
151161
*/
152-
public function providerV2(Request $request, Organization $organization, string $package): JsonResponse
162+
public function providerV2(Request $request, Organization $organization, string $package): Response
153163
{
154-
[$lastModified, $providerData] = $this->packageManager->findProviders(
164+
[$lastModified, $loader] = $this->packageManager->findProviders(
155165
$organization->alias(),
156166
[new PackageName('', $package)]
157167
);
158168

159-
if ($providerData === []) {
169+
if ($lastModified === null) {
160170
throw new NotFoundHttpException();
161171
}
162172

163-
$response = (new JsonResponse($providerData))
173+
$response = (new StreamedResponse(function () use ($loader): void {
174+
$outputStream = \fopen('php://output', 'wb');
175+
if (false === $outputStream) {
176+
throw new HttpException(500, 'Could not open output stream to send binary file.'); // @codeCoverageIgnore
177+
}
178+
179+
\fwrite($outputStream, ' ');
180+
\flush();
181+
\fwrite($outputStream, \json_encode($loader(), JsonResponse::DEFAULT_ENCODING_OPTIONS));
182+
}, Response::HTTP_OK, ['Content-Type' => 'application/json', 'X-Accel-Buffering' => 'no']))
164183
->setLastModified($lastModified)
165184
->setPrivate();
166185

src/Service/Organization/PackageManager.php

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ public function __construct(Storage $distStorage, FilesystemInterface $repoFiles
2828
/**
2929
* @param PackageName[] $packages
3030
*
31-
* @return array{\DateTimeImmutable|null, mixed[]}
31+
* @return array{\DateTimeImmutable|null, callable(): mixed[]}
3232
*/
3333
public function findProviders(string $organizationAlias, array $packages): array
3434
{
35-
$data = [];
3635
$lastModified = null;
36+
$filepaths = [];
3737

3838
foreach ($packages as $package) {
3939
$filepath = $this->filepath($organizationAlias, $package->name());
@@ -47,15 +47,22 @@ public function findProviders(string $organizationAlias, array $packages): array
4747
$lastModified = $fileModifyDate;
4848
}
4949

50-
$json = \unserialize(
51-
(string) $this->repoFilesystem->read($filepath), ['allowed_classes' => false]
52-
);
53-
$data[] = $json['packages'] ?? [];
50+
$filepaths[] = $filepath;
5451
}
5552

53+
$loader = function () use ($filepaths): array {
54+
$data = [];
55+
foreach ($filepaths as $filepath) {
56+
$json = \unserialize((string) $this->repoFilesystem->read($filepath), ['allowed_classes' => false]);
57+
$data[] = $json['packages'] ?? [];
58+
}
59+
60+
return \array_merge(...$data);
61+
};
62+
5663
return [
5764
$lastModified,
58-
\array_merge(...$data),
65+
$loader,
5966
];
6067
}
6168

src/Service/Security/PackageScanner/SensioLabsPackageScanner.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,12 @@ private function findDistribution(Package $package): string
112112
$normalizedVersion = $latestReleasedVersion === 'no stable release' ?
113113
'9999999-dev' : $this->versionParser->normalize((string) $latestReleasedVersion);
114114

115-
[, $providerData] = $this->packageManager->findProviders(
115+
[, $loader] = $this->packageManager->findProviders(
116116
$package->organizationAlias(),
117117
[new PackageName($package->id()->toString(), (string) $package->name())]
118118
);
119119

120+
$providerData = $loader();
120121
foreach ($providerData[$packageName] ?? [] as $packageData) {
121122
$packageVersion = $packageData['version_normalized']
122123
??

tests/Unit/Service/Organization/PackageManagerTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public function testFindProvidersForPackage(): void
5353
'reference' => 'ac7dcaf888af2324cd14200769362129c8dd8550',
5454
],
5555
'version_normalized' => '1.2.3.0',
56-
]]], $providers);
56+
]]], $providers());
5757
}
5858

5959
public function testReturnDistributionFilenameWhenExist(): void

0 commit comments

Comments
 (0)