/**
  * Retrieve a package.
  *
  * @param string $vendor  The name of the vendor.
  *
  * @param string $package The name of the package.
  *
  * @return JsonResponse
  *
  * @throws NotFoundHttpException When the package has not been found.
  *
  * @ApiDoc(
  *   section="package",
  *   statusCodes = {
  *     200 = "When everything worked out ok"
  *   },
  *   authentication = true,
  *   authenticationRoles = {
  *     "ROLE_MANIPULATE_REQUIREMENTS"
  *   }
  * )
  * @ApiDescription(
  *   response={
  *     "name" = {
  *       "dataType" = "string",
  *       "description" = "The name of the package"
  *     },
  *     "version" = {
  *       "dataType" = "string",
  *       "description" = "The version of the package"
  *     },
  *     "constraint" = {
  *       "dataType" = "string",
  *       "description" = "The constraint of the package (when package is installed)"
  *     },
  *     "type" = {
  *       "dataType" = "string",
  *       "description" = "The noted package type"
  *     },
  *     "locked" = {
  *       "dataType" = "string",
  *       "description" = "Flag if the package has been locked for updates"
  *     },
  *     "time" = {
  *       "dataType" = "datetime",
  *       "description" = "The release date"
  *     },
  *     "upgrade_version" = {
  *       "dataType" = "string",
  *       "description" = "The version available for upgrade (optional, if any)"
  *     },
  *     "description" = {
  *       "dataType" = "string",
  *       "description" = "The package description"
  *     },
  *     "license" = {
  *       "actualType" = "collection",
  *       "subType" = "string",
  *       "description" = "The licenses"
  *     },
  *     "keywords" = {
  *       "actualType" = "collection",
  *       "subType" = "string",
  *       "description" = "The keywords"
  *     },
  *     "homepage" = {
  *       "dataType" = "string",
  *       "description" = "The support website (optional, if any)"
  *     },
  *     "authors" = {
  *       "actualType" = "collection",
  *       "subType" = "object",
  *       "description" = "The authors",
  *       "children" = {
  *         "name" = {
  *           "dataType" = "string",
  *           "description" = "Full name of the author (optional, if any)"
  *         },
  *         "homepage" = {
  *           "dataType" = "string",
  *           "description" = "Email address of the author (optional, if any)"
  *         },
  *         "email" = {
  *           "dataType" = "string",
  *           "description" = "Homepage URL for the author (optional, if any)"
  *         },
  *         "role" = {
  *           "dataType" = "string",
  *           "description" = "Author's role in the project (optional, if any)"
  *         }
  *       }
  *     },
  *     "support" = {
  *       "actualType" = "collection",
  *       "subType" = "object",
  *       "description" = "The support options",
  *       "children" = {
  *         "email" = {
  *           "dataType" = "string",
  *           "description" = "Email address for support (optional, if any)"
  *         },
  *         "issues" = {
  *           "dataType" = "string",
  *           "description" = "URL to the issue tracker (optional, if any)"
  *         },
  *         "forum" = {
  *           "dataType" = "string",
  *           "description" = "URL to the forum (optional, if any)"
  *         },
  *         "wiki" = {
  *           "dataType" = "string",
  *           "description" = "URL to the wiki (optional, if any)"
  *         },
  *         "irc" = {
  *           "dataType" = "string",
  *           "description" = "IRC channel for support, as irc://server/channel (optional, if any)"
  *         },
  *         "source" = {
  *           "dataType" = "string",
  *           "description" = "URL to browse or download the sources (optional, if any)"
  *         },
  *         "docs" = {
  *           "dataType" = "string",
  *           "description" = "URL to the documentation (optional, if any)"
  *         },
  *       }
  *     },
  *     "abandoned" = {
  *       "dataType" = "boolean",
  *       "description" = "Flag if this package is abandoned"
  *     },
  *     "replacement" = {
  *       "dataType" = "string",
  *       "description" = "Replacement for this package (optional, if any)"
  *     }
  *   }
  * )
  */
 public function getPackageAction($vendor, $package)
 {
     $packageName = $vendor . '/' . $package;
     $composer = $this->getComposer();
     if ($package = $this->findPackage($packageName, $composer->getRepositoryManager()->getLocalRepository())) {
         $converter = new PackageConverter($composer->getPackage());
         return new JsonResponse($converter->convertPackageToArray($package), 200);
     }
     throw new NotFoundHttpException('Package ' . $packageName . ' not found.');
 }
 /**
  * Search for packages.
  *
  * @param Request $request The search request.
  *
  * @return JsonResponse
  *
  * @ApiDoc(
  *   section="search",
  *   statusCodes = {
  *     200 = "When everything worked out ok"
  *   },
  *   authentication = true,
  *   authenticationRoles = {
  *     "ROLE_MANIPULATE_REQUIREMENTS"
  *   }
  * )
  * @ApiDescription(
  *   request={
  *    "keywords" = {
  *      "dataType" = "string",
  *      "description" = "The name of the project to search or any other keyword.",
  *      "required" = true
  *    },
  *    "type" = {
  *      "dataType" = "choice",
  *      "description" = "The type of package to search (optional, default: all).",
  *      "format" = "['installed', 'contao', 'all']",
  *      "required" = false
  *    },
  *    "threshold" = {
  *      "dataType" = "int",
  *      "description" = "The amount of results after which the search shall be stopped (optional, default: 20).",
  *      "required" = false
  *    }
  *   },
  *   response={
  *     "package name 1...n" = {
  *       "actualType" = "object",
  *       "subType" = "object",
  *       "description" = "The content of the packages",
  *       "children" = {
  *         "name" = {
  *           "dataType" = "string",
  *           "description" = "The name of the package"
  *         },
  *         "version" = {
  *           "dataType" = "string",
  *           "description" = "The version of the package"
  *         },
  *         "constraint" = {
  *           "dataType" = "string",
  *           "description" = "The constraint of the package (when package is installed)"
  *         },
  *         "type" = {
  *           "dataType" = "string",
  *           "description" = "The noted package type"
  *         },
  *         "locked" = {
  *           "dataType" = "string",
  *           "description" = "Flag if the package has been locked for updates"
  *         },
  *         "time" = {
  *           "dataType" = "datetime",
  *           "description" = "The release date"
  *         },
  *         "upgrade_version" = {
  *           "dataType" = "string",
  *           "description" = "The version available for upgrade (optional, if any)"
  *         },
  *         "description" = {
  *           "dataType" = "string",
  *           "description" = "The package description"
  *         },
  *         "license" = {
  *           "actualType" = "collection",
  *           "subType" = "string",
  *           "description" = "The licenses"
  *         },
  *         "keywords" = {
  *           "actualType" = "collection",
  *           "subType" = "string",
  *           "description" = "The keywords"
  *         },
  *         "homepage" = {
  *           "dataType" = "string",
  *           "description" = "The support website (optional, if any)"
  *         },
  *         "authors" = {
  *           "actualType" = "collection",
  *           "subType" = "object",
  *           "description" = "The authors",
  *           "children" = {
  *             "name" = {
  *               "dataType" = "string",
  *               "description" = "Full name of the author (optional, if any)"
  *             },
  *             "homepage" = {
  *               "dataType" = "string",
  *               "description" = "Email address of the author (optional, if any)"
  *             },
  *             "email" = {
  *               "dataType" = "string",
  *               "description" = "Homepage URL for the author (optional, if any)"
  *             },
  *             "role" = {
  *               "dataType" = "string",
  *               "description" = "Author's role in the project (optional, if any)"
  *             }
  *           }
  *         },
  *         "support" = {
  *           "actualType" = "collection",
  *           "subType" = "object",
  *           "description" = "The support options",
  *           "children" = {
  *             "email" = {
  *               "dataType" = "string",
  *               "description" = "Email address for support (optional, if any)"
  *             },
  *             "issues" = {
  *               "dataType" = "string",
  *               "description" = "URL to the issue tracker (optional, if any)"
  *             },
  *             "forum" = {
  *               "dataType" = "string",
  *               "description" = "URL to the forum (optional, if any)"
  *             },
  *             "wiki" = {
  *               "dataType" = "string",
  *               "description" = "URL to the wiki (optional, if any)"
  *             },
  *             "irc" = {
  *               "dataType" = "string",
  *               "description" = "IRC channel for support, as irc://server/channel (optional, if any)"
  *             },
  *             "source" = {
  *               "dataType" = "string",
  *               "description" = "URL to browse or download the sources (optional, if any)"
  *             },
  *             "docs" = {
  *               "dataType" = "string",
  *               "description" = "URL to the documentation (optional, if any)"
  *             },
  *           }
  *         },
  *         "abandoned" = {
  *           "dataType" = "boolean",
  *           "description" = "Flag if this package is abandoned"
  *         },
  *         "replacement" = {
  *           "dataType" = "string",
  *           "description" = "Replacement for this package (optional, if any)"
  *         },
  *         "installed" = {
  *           "dataType" = "int",
  *           "description" = "Amount of installations"
  *         },
  *         "downloads" = {
  *           "dataType" = "int",
  *           "description" = "Amount of downloads"
  *         },
  *         "favers" = {
  *           "dataType" = "int",
  *           "description" = "Amount of favers"
  *         },
  *       }
  *     }
  *   }
  * )
  */
 public function searchAction(Request $request)
 {
     $composer = $this->getComposer();
     $data = new JsonArray($request->getContent());
     $keywords = $data->get('keywords');
     $type = $data->get('type');
     $threshold = $data->has('threshold') ? $data->get('threshold') : 20;
     $localRepository = $composer->getRepositoryManager()->getLocalRepository();
     $searcher = $this->getRepositorySearch($keywords, $type, $composer, $threshold);
     $results = $searcher->searchAndDecorate($keywords, $this->getFilters($type));
     $responseData = [];
     $rootPackage = $composer->getPackage();
     $converter = new PackageConverter($rootPackage);
     foreach ($results as $versionedResult) {
         /** @var VersionedPackage $versionedResult */
         // Might have no version matching the current stability setting.
         if (null === ($latestVersion = $versionedResult->getLatestVersion())) {
             continue;
         }
         $package = $converter->convertPackageToArray($latestVersion);
         $package->set('installed', $this->getInstalledVersion($localRepository, $versionedResult->getName()))->set('downloads', $versionedResult->getMetaData('downloads'))->set('favers', $versionedResult->getMetaData('favers'));
         $responseData[$package->get('name')] = $package->getData();
     }
     return JsonResponse::create($responseData)->setEncodingOptions(JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_FORCE_OBJECT);
 }