FeedController.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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 Symfony\Bundle\FrameworkBundle\Controller\Controller;
  13. use Doctrine\ORM\QueryBuilder;
  14. use Pagerfanta\Adapter\DoctrineORMAdapter;
  15. use Pagerfanta\Pagerfanta;
  16. use Zend\Feed\Writer\Entry;
  17. use Zend\Feed\Writer\Feed;
  18. use Packagist\WebBundle\Entity\Package;
  19. use Packagist\WebBundle\Entity\Version;
  20. use Symfony\Component\HttpFoundation\Response;
  21. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
  22. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
  23. /**
  24. * @author Rafael Dohms <rafael@doh.ms>
  25. *
  26. * @Route("/feeds")
  27. */
  28. class FeedController extends Controller
  29. {
  30. /**
  31. * @Route(
  32. * "/packages.{_format}",
  33. * name="feed_packages",
  34. * requirements={"_format"="(rss|atom)"}
  35. * )
  36. * @Method({"GET"})
  37. */
  38. public function packagesAction()
  39. {
  40. /** @var $repo \Packagist\WebBundle\Entity\VersionRepository */
  41. $repo = $this->getDoctrine()->getRepository('PackagistWebBundle:Package');
  42. $packages = $this->getLimitedResults(
  43. $repo->getQueryBuilderForNewestPackages()
  44. );
  45. $feed = $this->buildFeed(
  46. 'Newly Submitted Packages',
  47. 'Latest packages submitted to Packagist.',
  48. $this->generateUrl('browse', array(), true),
  49. $packages
  50. );
  51. return $this->buildResponse($feed);
  52. }
  53. /**
  54. * @Route(
  55. * "/releases.{_format}",
  56. * name="feed_releases",
  57. * requirements={"_format"="(rss|atom)"}
  58. * )
  59. * @Method({"GET"})
  60. */
  61. public function releasesAction()
  62. {
  63. /** @var $repo \Packagist\WebBundle\Entity\PackageRepository */
  64. $repo = $this->getDoctrine()->getRepository('PackagistWebBundle:Version');
  65. $packages = $this->getLimitedResults(
  66. $repo->getQueryBuilderForLatestVersionWithPackage()
  67. );
  68. $feed = $this->buildFeed(
  69. 'New Releases',
  70. 'Latest releases of all packages.',
  71. $this->generateUrl('browse', array(), true),
  72. $packages
  73. );
  74. return $this->buildResponse($feed);
  75. }
  76. /**
  77. * @Route(
  78. * "/vendor.{vendor}.{_format}",
  79. * name="feed_vendor",
  80. * requirements={"_format"="(rss|atom)", "vendor"="[A-Za-z0-9_.-]+"}
  81. * )
  82. * @Method({"GET"})
  83. */
  84. public function vendorAction($vendor)
  85. {
  86. /** @var $repo \Packagist\WebBundle\Entity\PackageRepository */
  87. $repo = $this->getDoctrine()->getRepository('PackagistWebBundle:Version');
  88. $packages = $this->getLimitedResults(
  89. $repo->getQueryBuilderForLatestVersionWithPackage($vendor)
  90. );
  91. $feed = $this->buildFeed(
  92. "$vendor packages",
  93. "Latest packages updated on Packagist of $vendor.",
  94. $this->generateUrl('view_vendor', array('vendor' => $vendor), true),
  95. $packages
  96. );
  97. return $this->buildResponse($feed);
  98. }
  99. /**
  100. * Limits a query to the desired number of results
  101. *
  102. * @param \Doctrine\ORM\QueryBuilder $queryBuilder
  103. *
  104. * @return array|\Traversable
  105. */
  106. protected function getLimitedResults(QueryBuilder $queryBuilder)
  107. {
  108. $paginator = new Pagerfanta(new DoctrineORMAdapter($queryBuilder));
  109. $paginator->setMaxPerPage(
  110. $this->container->getParameter('packagist_web.rss_max_items')
  111. );
  112. $paginator->setCurrentPage(1);
  113. return $paginator->getCurrentPageResults();
  114. }
  115. /**
  116. * Builds the desired feed
  117. *
  118. * @param string $title
  119. * @param string $description
  120. * @param array $items
  121. *
  122. * @return \Zend\Feed\Writer\Feed
  123. */
  124. protected function buildFeed($title, $description, $url, $items)
  125. {
  126. $feed = new Feed();
  127. $feed->setTitle($title);
  128. $feed->setDescription($description);
  129. $feed->setLink($url);
  130. foreach ($items as $item) {
  131. $entry = $feed->createEntry();
  132. $this->populateEntry($entry, $item);
  133. $feed->addEntry($entry);
  134. }
  135. if ($this->getRequest()->getRequestFormat() == 'atom') {
  136. $feed->setFeedLink(
  137. $this->getRequest()->getUri(),
  138. $this->getRequest()->getRequestFormat()
  139. );
  140. }
  141. $feed->setDateModified($feed->getEntry(0)->getDateModified());
  142. return $feed;
  143. }
  144. /**
  145. * Receives either a Package or a Version and populates a feed entry.
  146. *
  147. * @param \Zend\Feed\Writer\Entry $entry
  148. * @param Package|Version $item
  149. */
  150. protected function populateEntry(Entry $entry, $item)
  151. {
  152. if ($item instanceof Package) {
  153. $this->populatePackageData($entry, $item);
  154. } elseif ($item instanceof Version) {
  155. $this->populatePackageData($entry, $item->getPackage());
  156. $this->populateVersionData($entry, $item);
  157. }
  158. }
  159. /**
  160. * Populates a feed entry with data coming from Package objects.
  161. *
  162. * @param \Zend\Feed\Writer\Entry $entry
  163. * @param Package $package
  164. */
  165. protected function populatePackageData(Entry $entry, Package $package)
  166. {
  167. $entry->setTitle($package->getName());
  168. $entry->setLink(
  169. $this->generateUrl(
  170. 'view_package',
  171. array('name' => $package->getName()),
  172. true
  173. )
  174. );
  175. $entry->setDateModified($package->getCreatedAt());
  176. $entry->setDateCreated($package->getCreatedAt());
  177. $entry->setDescription($package->getDescription() ?: ' ');
  178. }
  179. /**
  180. * Populates a feed entry with data coming from Version objects.
  181. *
  182. * @param \Zend\Feed\Writer\Entry $entry
  183. * @param Version $version
  184. */
  185. protected function populateVersionData(Entry $entry, Version $version)
  186. {
  187. $entry->setTitle($entry->getTitle()." ({$version->getVersion()})");
  188. $entry->setDateModified($version->getReleasedAt());
  189. $entry->setDateCreated($version->getReleasedAt());
  190. foreach ($version->getAuthors() as $author) {
  191. /** @var $author \Packagist\WebBundle\Entity\Author */
  192. if ($author->getName()) {
  193. $entry->addAuthor(array(
  194. 'name' => $author->getName()
  195. ));
  196. }
  197. }
  198. }
  199. /**
  200. * Creates a HTTP Response and exports feed
  201. *
  202. * @param \Zend\Feed\Writer\Feed $feed
  203. *
  204. * @return \Symfony\Component\HttpFoundation\Response
  205. */
  206. protected function buildResponse(Feed $feed)
  207. {
  208. $content = $feed->export($this->getRequest()->getRequestFormat());
  209. $response = new Response($content, 200);
  210. $response->setSharedMaxAge(3600);
  211. return $response;
  212. }
  213. }