ExploreController.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <?php
  2. /*
  3. * This file is part of Packagist.
  4. *
  5. * (c) Jordi Boggiano <j.boggiano@seld.be>
  6. * Nils Adermann <naderman@naderman.de>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Packagist\WebBundle\Controller;
  12. use Doctrine\DBAL\ConnectionException;
  13. use Packagist\WebBundle\Entity\Package;
  14. use Packagist\WebBundle\Entity\PackageRepository;
  15. use Packagist\WebBundle\Entity\VersionRepository;
  16. use Pagerfanta\Adapter\FixedAdapter;
  17. use Pagerfanta\Pagerfanta;
  18. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
  19. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
  20. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
  21. use Symfony\Component\HttpFoundation\JsonResponse;
  22. use Symfony\Component\HttpFoundation\Request;
  23. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  24. /**
  25. * @Route("/explore")
  26. */
  27. class ExploreController extends Controller
  28. {
  29. /**
  30. * @Template()
  31. * @Route("/", name="browse")
  32. */
  33. public function exploreAction()
  34. {
  35. /** @var PackageRepository $pkgRepo */
  36. $pkgRepo = $this->getDoctrine()->getRepository('PackagistWebBundle:Package');
  37. /** @var VersionRepository $verRepo */
  38. $verRepo = $this->get('packagist.version_repository');
  39. $newSubmitted = $pkgRepo->getQueryBuilderForNewestPackages()->setMaxResults(10)
  40. ->getQuery()->useResultCache(true, 900)->getResult();
  41. $newReleases = $verRepo->getLatestReleases(10);
  42. $randomIds = $this->getDoctrine()->getConnection()->fetchAll('SELECT id FROM package ORDER BY RAND() LIMIT 10');
  43. $random = $pkgRepo->createQueryBuilder('p')->where('p.id IN (:ids)')->setParameter('ids', $randomIds)->getQuery()->getResult();
  44. try {
  45. $popular = array();
  46. $popularIds = $this->get('snc_redis.default')->zrevrange('downloads:trending', 0, 9);
  47. if ($popularIds) {
  48. $popular = $pkgRepo->createQueryBuilder('p')->where('p.id IN (:ids)')->setParameter('ids', $popularIds)
  49. ->getQuery()->useResultCache(true, 900)->getResult();
  50. usort($popular, function ($a, $b) use ($popularIds) {
  51. return array_search($a->getId(), $popularIds) > array_search($b->getId(), $popularIds) ? 1 : -1;
  52. });
  53. }
  54. } catch (ConnectionException $e) {
  55. $popular = array();
  56. }
  57. $data = array(
  58. 'newlySubmitted' => $newSubmitted,
  59. 'newlyReleased' => $newReleases,
  60. 'random' => $random,
  61. 'popular' => $popular,
  62. );
  63. return $data;
  64. }
  65. /**
  66. * @Template()
  67. * @Route("/popular.{_format}", name="browse_popular", defaults={"_format"="html"})
  68. * @Cache(smaxage=900)
  69. */
  70. public function popularAction(Request $req)
  71. {
  72. try {
  73. $redis = $this->get('snc_redis.default');
  74. $perPage = $req->query->getInt('per_page', 15);
  75. if ($perPage <= 0 || $perPage > 100) {
  76. if ($req->getRequestFormat() === 'json') {
  77. return new JsonResponse(array(
  78. 'status' => 'error',
  79. 'message' => 'The optional packages per_page parameter must be an integer between 1 and 100 (default: 15)',
  80. ), 400);
  81. }
  82. $perPage = max(0, min(100, $perPage));
  83. }
  84. $popularIds = $redis->zrevrange(
  85. 'downloads:trending',
  86. ($req->get('page', 1) - 1) * $perPage,
  87. $req->get('page', 1) * $perPage - 1
  88. );
  89. $popular = $this->getDoctrine()->getRepository('PackagistWebBundle:Package')
  90. ->createQueryBuilder('p')->where('p.id IN (:ids)')->setParameter('ids', $popularIds)
  91. ->getQuery()->useResultCache(true, 900)->getResult();
  92. usort($popular, function ($a, $b) use ($popularIds) {
  93. return array_search($a->getId(), $popularIds) > array_search($b->getId(), $popularIds) ? 1 : -1;
  94. });
  95. $packages = new Pagerfanta(new FixedAdapter($redis->zcard('downloads:trending'), $popular));
  96. $packages->setMaxPerPage($perPage);
  97. $packages->setCurrentPage($req->get('page', 1), false, true);
  98. } catch (ConnectionException $e) {
  99. $packages = new Pagerfanta(new FixedAdapter(0, array()));
  100. }
  101. $data = array(
  102. 'packages' => $packages,
  103. );
  104. $data['meta'] = $this->getPackagesMetadata($data['packages']);
  105. if ($req->getRequestFormat() === 'json') {
  106. $result = array(
  107. 'packages' => array(),
  108. 'total' => $packages->getNbResults(),
  109. );
  110. /** @var Package $package */
  111. foreach ($packages as $package) {
  112. $url = $this->generateUrl('view_package', array('name' => $package->getName()), UrlGeneratorInterface::ABSOLUTE_URL);
  113. $result['packages'][] = array(
  114. 'name' => $package->getName(),
  115. 'description' => $package->getDescription() ?: '',
  116. 'url' => $url,
  117. 'downloads' => $data['meta']['downloads'][$package->getId()],
  118. 'favers' => $data['meta']['favers'][$package->getId()],
  119. );
  120. }
  121. if ($packages->hasNextPage()) {
  122. $params = array(
  123. '_format' => 'json',
  124. 'page' => $packages->getNextPage(),
  125. );
  126. if ($perPage !== 15) {
  127. $params['per_page'] = $perPage;
  128. }
  129. $result['next'] = $this->generateUrl('browse_popular', $params, UrlGeneratorInterface::ABSOLUTE_URL);
  130. }
  131. return new JsonResponse($result);
  132. }
  133. return $data;
  134. }
  135. }