1 | <?php |
||
42 | class PackageController extends AbstractController |
||
43 | { |
||
44 | /** |
||
45 | * Retrieve the package list. |
||
46 | * |
||
47 | * @param Request $request The request to process. |
||
48 | * |
||
49 | * @return JsonResponse |
||
50 | * |
||
51 | * @ApiDoc( |
||
52 | * section="package", |
||
53 | * statusCodes = { |
||
54 | * 200 = "When everything worked out ok" |
||
55 | * }, |
||
56 | * authentication = true, |
||
57 | * authenticationRoles = { |
||
58 | * "ROLE_MANIPULATE_REQUIREMENTS" |
||
59 | * }, |
||
60 | * filters = { |
||
61 | * { |
||
62 | * "name"="all", |
||
63 | * "description"="If present, all packages will get listed, only directly required ones otherwise." |
||
64 | * } |
||
65 | * } |
||
66 | * ) |
||
67 | * @ApiDescription( |
||
68 | * response={ |
||
69 | * "package name 1...n" = { |
||
70 | * "actualType" = "object", |
||
71 | * "subType" = "object", |
||
72 | * "description" = "The content of the packages", |
||
73 | * "children" = { |
||
74 | * "name" = { |
||
75 | * "dataType" = "string", |
||
76 | * "description" = "The name of the package" |
||
77 | * }, |
||
78 | * "version" = { |
||
79 | * "dataType" = "string", |
||
80 | * "description" = "The version of the package" |
||
81 | * }, |
||
82 | * "constraint" = { |
||
83 | * "dataType" = "string", |
||
84 | * "description" = "The constraint of the package (when package is installed)" |
||
85 | * }, |
||
86 | * "type" = { |
||
87 | * "dataType" = "string", |
||
88 | * "description" = "The noted package type" |
||
89 | * }, |
||
90 | * "locked" = { |
||
91 | * "dataType" = "string", |
||
92 | * "description" = "Flag if the package has been locked for updates" |
||
93 | * }, |
||
94 | * "time" = { |
||
95 | * "dataType" = "datetime", |
||
96 | * "description" = "The release date" |
||
97 | * }, |
||
98 | * "upgrade_version" = { |
||
99 | * "dataType" = "string", |
||
100 | * "description" = "The version available for upgrade (optional, if any)" |
||
101 | * }, |
||
102 | * "description" = { |
||
103 | * "dataType" = "string", |
||
104 | * "description" = "The package description" |
||
105 | * }, |
||
106 | * "license" = { |
||
107 | * "actualType" = "collection", |
||
108 | * "subType" = "string", |
||
109 | * "description" = "The licenses" |
||
110 | * }, |
||
111 | * "keywords" = { |
||
112 | * "actualType" = "collection", |
||
113 | * "subType" = "string", |
||
114 | * "description" = "The keywords" |
||
115 | * }, |
||
116 | * "homepage" = { |
||
117 | * "dataType" = "string", |
||
118 | * "description" = "The support website (optional, if any)" |
||
119 | * }, |
||
120 | * "authors" = { |
||
121 | * "actualType" = "collection", |
||
122 | * "subType" = "object", |
||
123 | * "description" = "The authors", |
||
124 | * "children" = { |
||
125 | * "name" = { |
||
126 | * "dataType" = "string", |
||
127 | * "description" = "Full name of the author (optional, if any)" |
||
128 | * }, |
||
129 | * "homepage" = { |
||
130 | * "dataType" = "string", |
||
131 | * "description" = "Email address of the author (optional, if any)" |
||
132 | * }, |
||
133 | * "email" = { |
||
134 | * "dataType" = "string", |
||
135 | * "description" = "Homepage URL for the author (optional, if any)" |
||
136 | * }, |
||
137 | * "role" = { |
||
138 | * "dataType" = "string", |
||
139 | * "description" = "Author's role in the project (optional, if any)" |
||
140 | * } |
||
141 | * } |
||
142 | * }, |
||
143 | * "support" = { |
||
144 | * "actualType" = "collection", |
||
145 | * "subType" = "object", |
||
146 | * "description" = "The support options", |
||
147 | * "children" = { |
||
148 | * "email" = { |
||
149 | * "dataType" = "string", |
||
150 | * "description" = "Email address for support (optional, if any)" |
||
151 | * }, |
||
152 | * "issues" = { |
||
153 | * "dataType" = "string", |
||
154 | * "description" = "URL to the issue tracker (optional, if any)" |
||
155 | * }, |
||
156 | * "forum" = { |
||
157 | * "dataType" = "string", |
||
158 | * "description" = "URL to the forum (optional, if any)" |
||
159 | * }, |
||
160 | * "wiki" = { |
||
161 | * "dataType" = "string", |
||
162 | * "description" = "URL to the wiki (optional, if any)" |
||
163 | * }, |
||
164 | * "irc" = { |
||
165 | * "dataType" = "string", |
||
166 | * "description" = "IRC channel for support, as irc://server/channel (optional, if any)" |
||
167 | * }, |
||
168 | * "source" = { |
||
169 | * "dataType" = "string", |
||
170 | * "description" = "URL to browse or download the sources (optional, if any)" |
||
171 | * }, |
||
172 | * "docs" = { |
||
173 | * "dataType" = "string", |
||
174 | * "description" = "URL to the documentation (optional, if any)" |
||
175 | * }, |
||
176 | * } |
||
177 | * }, |
||
178 | * "extra" = { |
||
179 | * "dataType" = "collection", |
||
180 | * "description" = "The extra data from composer.json" |
||
181 | * }, |
||
182 | * "abandoned" = { |
||
183 | * "dataType" = "boolean", |
||
184 | * "description" = "Flag if this package is abandoned" |
||
185 | * }, |
||
186 | * "replacement" = { |
||
187 | * "dataType" = "string", |
||
188 | * "description" = "Replacement for this package (optional, if any)" |
||
189 | * } |
||
190 | * } |
||
191 | * } |
||
192 | * } |
||
193 | * ) |
||
194 | */ |
||
195 | public function packageListAction(Request $request) |
||
196 | { |
||
197 | $composer = $this->getComposer(); |
||
198 | $converter = new PackageConverter($composer->getPackage()); |
||
199 | $upgrades = $this->getUpgradeRepository(); |
||
200 | $packages = $converter->convertRepositoryToArray( |
||
201 | $composer->getRepositoryManager()->getLocalRepository(), |
||
202 | !$request->query->has('all'), |
||
203 | $upgrades |
||
204 | )->getData(); |
||
205 | ksort($packages); |
||
206 | |||
207 | return new JsonResponse($packages, 200); |
||
208 | } |
||
209 | |||
210 | /** |
||
211 | * Retrieve a package. |
||
212 | * |
||
213 | * @param string $vendor The name of the vendor. |
||
214 | * |
||
215 | * @param string $package The name of the package. |
||
216 | * |
||
217 | * @return JsonResponse |
||
218 | * |
||
219 | * @throws NotFoundHttpException When the package has not been found. |
||
220 | * |
||
221 | * @ApiDoc( |
||
222 | * section="package", |
||
223 | * statusCodes = { |
||
224 | * 200 = "When everything worked out ok" |
||
225 | * }, |
||
226 | * authentication = true, |
||
227 | * authenticationRoles = { |
||
228 | * "ROLE_MANIPULATE_REQUIREMENTS" |
||
229 | * } |
||
230 | * ) |
||
231 | * @ApiDescription( |
||
232 | * response={ |
||
233 | * "name" = { |
||
234 | * "dataType" = "string", |
||
235 | * "description" = "The name of the package" |
||
236 | * }, |
||
237 | * "version" = { |
||
238 | * "dataType" = "string", |
||
239 | * "description" = "The version of the package" |
||
240 | * }, |
||
241 | * "constraint" = { |
||
242 | * "dataType" = "string", |
||
243 | * "description" = "The constraint of the package (when package is installed)" |
||
244 | * }, |
||
245 | * "type" = { |
||
246 | * "dataType" = "string", |
||
247 | * "description" = "The noted package type" |
||
248 | * }, |
||
249 | * "locked" = { |
||
250 | * "dataType" = "string", |
||
251 | * "description" = "Flag if the package has been locked for updates" |
||
252 | * }, |
||
253 | * "time" = { |
||
254 | * "dataType" = "datetime", |
||
255 | * "description" = "The release date" |
||
256 | * }, |
||
257 | * "upgrade_version" = { |
||
258 | * "dataType" = "string", |
||
259 | * "description" = "The version available for upgrade (optional, if any)" |
||
260 | * }, |
||
261 | * "description" = { |
||
262 | * "dataType" = "string", |
||
263 | * "description" = "The package description" |
||
264 | * }, |
||
265 | * "license" = { |
||
266 | * "actualType" = "collection", |
||
267 | * "subType" = "string", |
||
268 | * "description" = "The licenses" |
||
269 | * }, |
||
270 | * "keywords" = { |
||
271 | * "actualType" = "collection", |
||
272 | * "subType" = "string", |
||
273 | * "description" = "The keywords" |
||
274 | * }, |
||
275 | * "homepage" = { |
||
276 | * "dataType" = "string", |
||
277 | * "description" = "The support website (optional, if any)" |
||
278 | * }, |
||
279 | * "authors" = { |
||
280 | * "actualType" = "collection", |
||
281 | * "subType" = "object", |
||
282 | * "description" = "The authors", |
||
283 | * "children" = { |
||
284 | * "name" = { |
||
285 | * "dataType" = "string", |
||
286 | * "description" = "Full name of the author (optional, if any)" |
||
287 | * }, |
||
288 | * "homepage" = { |
||
289 | * "dataType" = "string", |
||
290 | * "description" = "Email address of the author (optional, if any)" |
||
291 | * }, |
||
292 | * "email" = { |
||
293 | * "dataType" = "string", |
||
294 | * "description" = "Homepage URL for the author (optional, if any)" |
||
295 | * }, |
||
296 | * "role" = { |
||
297 | * "dataType" = "string", |
||
298 | * "description" = "Author's role in the project (optional, if any)" |
||
299 | * } |
||
300 | * } |
||
301 | * }, |
||
302 | * "support" = { |
||
303 | * "actualType" = "collection", |
||
304 | * "subType" = "object", |
||
305 | * "description" = "The support options", |
||
306 | * "children" = { |
||
307 | * "email" = { |
||
308 | * "dataType" = "string", |
||
309 | * "description" = "Email address for support (optional, if any)" |
||
310 | * }, |
||
311 | * "issues" = { |
||
312 | * "dataType" = "string", |
||
313 | * "description" = "URL to the issue tracker (optional, if any)" |
||
314 | * }, |
||
315 | * "forum" = { |
||
316 | * "dataType" = "string", |
||
317 | * "description" = "URL to the forum (optional, if any)" |
||
318 | * }, |
||
319 | * "wiki" = { |
||
320 | * "dataType" = "string", |
||
321 | * "description" = "URL to the wiki (optional, if any)" |
||
322 | * }, |
||
323 | * "irc" = { |
||
324 | * "dataType" = "string", |
||
325 | * "description" = "IRC channel for support, as irc://server/channel (optional, if any)" |
||
326 | * }, |
||
327 | * "source" = { |
||
328 | * "dataType" = "string", |
||
329 | * "description" = "URL to browse or download the sources (optional, if any)" |
||
330 | * }, |
||
331 | * "docs" = { |
||
332 | * "dataType" = "string", |
||
333 | * "description" = "URL to the documentation (optional, if any)" |
||
334 | * }, |
||
335 | * } |
||
336 | * }, |
||
337 | * "abandoned" = { |
||
338 | * "dataType" = "boolean", |
||
339 | * "description" = "Flag if this package is abandoned" |
||
340 | * }, |
||
341 | * "replacement" = { |
||
342 | * "dataType" = "string", |
||
343 | * "description" = "Replacement for this package (optional, if any)" |
||
344 | * } |
||
345 | * } |
||
346 | * ) |
||
347 | */ |
||
348 | public function getPackageAction($vendor, $package) |
||
349 | { |
||
350 | $packageName = $vendor . '/' . $package; |
||
351 | $composer = $this->getComposer(); |
||
352 | |||
353 | if ($package = $this->findPackage($packageName, $composer->getRepositoryManager()->getLocalRepository())) { |
||
354 | $converter = new PackageConverter($composer->getPackage()); |
||
355 | return new JsonResponse($converter->convertPackageToArray($package), 200); |
||
356 | } |
||
357 | |||
358 | throw new NotFoundHttpException('Package ' . $packageName . ' not found.'); |
||
359 | } |
||
360 | |||
361 | /** |
||
362 | * Update the information of a package in the composer.json. |
||
363 | * |
||
364 | * Note that the payload name of the package must match the vendor and package passed as parameter. |
||
365 | * |
||
366 | * @param string $vendor The name of the vendor. |
||
367 | * |
||
368 | * @param string $package The name of the package. |
||
369 | * |
||
370 | * @param Request $request The request to process. |
||
371 | * |
||
372 | * @return JsonResponse |
||
373 | * |
||
374 | * @throws NotAcceptableHttpException When the passed payload is invalid. |
||
375 | * @throws NotFoundHttpException When the package has not been found. |
||
376 | * |
||
377 | * @ApiDoc( |
||
378 | * section="package", |
||
379 | * statusCodes = { |
||
380 | * 200 = "When everything worked out ok" |
||
381 | * }, |
||
382 | * authentication = true, |
||
383 | * authenticationRoles = { |
||
384 | * "ROLE_MANIPULATE_REQUIREMENTS" |
||
385 | * } |
||
386 | * ) |
||
387 | * |
||
388 | * @ApiDescription( |
||
389 | * request={ |
||
390 | * "name" = { |
||
391 | * "dataType" = "string", |
||
392 | * "description" = "The name of the package", |
||
393 | * "required" = true |
||
394 | * }, |
||
395 | * "constraint" = { |
||
396 | * "dataType" = "string", |
||
397 | * "description" = "The constraint of the package (when package is installed)", |
||
398 | * "required" = true |
||
399 | * }, |
||
400 | * "locked" = { |
||
401 | * "dataType" = "string", |
||
402 | * "description" = "Flag if the package has been locked for updates", |
||
403 | * "required" = true |
||
404 | * }, |
||
405 | * }, |
||
406 | * response={ |
||
407 | * "name" = { |
||
408 | * "dataType" = "string", |
||
409 | * "description" = "The name of the package" |
||
410 | * }, |
||
411 | * "version" = { |
||
412 | * "dataType" = "string", |
||
413 | * "description" = "The version of the package" |
||
414 | * }, |
||
415 | * "constraint" = { |
||
416 | * "dataType" = "string", |
||
417 | * "description" = "The constraint of the package (when package is installed)" |
||
418 | * }, |
||
419 | * "type" = { |
||
420 | * "dataType" = "string", |
||
421 | * "description" = "The noted package type" |
||
422 | * }, |
||
423 | * "locked" = { |
||
424 | * "dataType" = "string", |
||
425 | * "description" = "Flag if the package has been locked for updates" |
||
426 | * }, |
||
427 | * "time" = { |
||
428 | * "dataType" = "datetime", |
||
429 | * "description" = "The release date" |
||
430 | * }, |
||
431 | * "upgrade_version" = { |
||
432 | * "dataType" = "string", |
||
433 | * "description" = "The version available for upgrade (optional, if any)" |
||
434 | * }, |
||
435 | * "description" = { |
||
436 | * "dataType" = "string", |
||
437 | * "description" = "The package description" |
||
438 | * }, |
||
439 | * "license" = { |
||
440 | * "actualType" = "collection", |
||
441 | * "subType" = "string", |
||
442 | * "description" = "The licenses" |
||
443 | * }, |
||
444 | * "keywords" = { |
||
445 | * "actualType" = "collection", |
||
446 | * "subType" = "string", |
||
447 | * "description" = "The keywords" |
||
448 | * }, |
||
449 | * "homepage" = { |
||
450 | * "dataType" = "string", |
||
451 | * "description" = "The support website (optional, if any)" |
||
452 | * }, |
||
453 | * "authors" = { |
||
454 | * "actualType" = "collection", |
||
455 | * "subType" = "object", |
||
456 | * "description" = "The authors", |
||
457 | * "children" = { |
||
458 | * "name" = { |
||
459 | * "dataType" = "string", |
||
460 | * "description" = "Full name of the author (optional, if any)" |
||
461 | * }, |
||
462 | * "homepage" = { |
||
463 | * "dataType" = "string", |
||
464 | * "description" = "Email address of the author (optional, if any)" |
||
465 | * }, |
||
466 | * "email" = { |
||
467 | * "dataType" = "string", |
||
468 | * "description" = "Homepage URL for the author (optional, if any)" |
||
469 | * }, |
||
470 | * "role" = { |
||
471 | * "dataType" = "string", |
||
472 | * "description" = "Author's role in the project (optional, if any)" |
||
473 | * } |
||
474 | * } |
||
475 | * }, |
||
476 | * "support" = { |
||
477 | * "actualType" = "collection", |
||
478 | * "subType" = "object", |
||
479 | * "description" = "The support options", |
||
480 | * "children" = { |
||
481 | * "email" = { |
||
482 | * "dataType" = "string", |
||
483 | * "description" = "Email address for support (optional, if any)" |
||
484 | * }, |
||
485 | * "issues" = { |
||
486 | * "dataType" = "string", |
||
487 | * "description" = "URL to the issue tracker (optional, if any)" |
||
488 | * }, |
||
489 | * "forum" = { |
||
490 | * "dataType" = "string", |
||
491 | * "description" = "URL to the forum (optional, if any)" |
||
492 | * }, |
||
493 | * "wiki" = { |
||
494 | * "dataType" = "string", |
||
495 | * "description" = "URL to the wiki (optional, if any)" |
||
496 | * }, |
||
497 | * "irc" = { |
||
498 | * "dataType" = "string", |
||
499 | * "description" = "IRC channel for support, as irc://server/channel (optional, if any)" |
||
500 | * }, |
||
501 | * "source" = { |
||
502 | * "dataType" = "string", |
||
503 | * "description" = "URL to browse or download the sources (optional, if any)" |
||
504 | * }, |
||
505 | * "docs" = { |
||
506 | * "dataType" = "string", |
||
507 | * "description" = "URL to the documentation (optional, if any)" |
||
508 | * }, |
||
509 | * } |
||
510 | * }, |
||
511 | * "abandoned" = { |
||
512 | * "dataType" = "boolean", |
||
513 | * "description" = "Flag if this package is abandoned" |
||
514 | * }, |
||
515 | * "replacement" = { |
||
516 | * "dataType" = "string", |
||
517 | * "description" = "Replacement for this package (optional, if any)" |
||
518 | * } |
||
519 | * } |
||
520 | * ) |
||
521 | */ |
||
522 | public function putPackageAction($vendor, $package, Request $request) |
||
523 | { |
||
524 | $packageName = $vendor . '/' . $package; |
||
525 | $info = new JsonArray($request->getContent()); |
||
|
|||
526 | $name = $info->get('name'); |
||
527 | |||
528 | if (!($info->has('name') && $info->has('locked') && $info->has('constraint'))) { |
||
529 | throw new NotAcceptableHttpException('Invalid package information.'); |
||
530 | } |
||
531 | |||
532 | if ($name !== $packageName) { |
||
533 | throw new NotAcceptableHttpException('Package name mismatch ' . $packageName . ' vs. ' . $name . '.'); |
||
534 | } |
||
535 | |||
536 | $composer = $this->getComposer(); |
||
537 | $json = $this->get('tenside.composer_json'); |
||
538 | |||
539 | $package = $this->findPackage($name, $composer->getRepositoryManager()->getLocalRepository()); |
||
540 | |||
541 | if (null === $package) { |
||
542 | throw new NotFoundHttpException('Package ' . $packageName . ' not found.'); |
||
543 | } |
||
544 | |||
545 | $json->setLock($package, $info->get('locked')); |
||
546 | return $this->forward('TensideCoreBundle:Package:getPackage'); |
||
547 | } |
||
548 | |||
549 | /** |
||
550 | * Search the repository for a package. |
||
551 | * |
||
552 | * @param string $name The pretty name of the package to search. |
||
553 | * |
||
554 | * @param RepositoryInterface $repository The repository to be searched. |
||
555 | * |
||
556 | * @return null|PackageInterface |
||
557 | */ |
||
558 | private function findPackage($name, RepositoryInterface $repository) |
||
559 | { |
||
560 | /** @var PackageInterface[] $packages */ |
||
561 | $packages = $repository->findPackages($name); |
||
562 | |||
563 | while (!empty($packages) && $packages[0] instanceof AliasPackage) { |
||
564 | array_shift($packages); |
||
565 | } |
||
566 | |||
567 | if (empty($packages)) { |
||
568 | return null; |
||
569 | } |
||
570 | |||
571 | return $packages[0]; |
||
572 | } |
||
573 | |||
574 | /** |
||
575 | * Load a repository containing available upgrades. |
||
576 | * |
||
577 | * @return null|RepositoryInterface |
||
578 | */ |
||
579 | private function getUpgradeRepository() |
||
597 | } |
||
598 |
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.