FeedController.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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 Composer\IO\NullIO;
  13. use Composer\Factory;
  14. use Composer\Package\Loader\ArrayLoader;
  15. use Packagist\WebBundle\Package\Updater;
  16. use Symfony\Bundle\FrameworkBundle\Controller\Controller;
  17. use Packagist\WebBundle\Entity\Package;
  18. use Packagist\WebBundle\Entity\Version;
  19. use Symfony\Component\HttpFoundation\RedirectResponse;
  20. use Symfony\Component\HttpFoundation\Response;
  21. use Symfony\Component\HttpFoundation\Request;
  22. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  23. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
  24. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
  25. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  26. /**
  27. * @author Rafael Dohms <rafael@doh.ms>
  28. *
  29. * @Route("/feeds")
  30. */
  31. class FeedController extends Controller
  32. {
  33. /**
  34. * @Route("/", name="feed_home")
  35. */
  36. public function indexAction()
  37. {
  38. return $this->forward('PackagistFeedController:Feed:latest');
  39. }
  40. /**
  41. * @Route(
  42. * "/packages.{format}",
  43. * name="feed_packages",
  44. * requirements={"format"="(rss|atom)"},
  45. * defaults={"format"="rss"}
  46. * )
  47. * @Method({"GET"})
  48. */
  49. public function packagesAction($format)
  50. {
  51. /** @var $repo \Packagist\WebBundle\Entity\VersionRepository */
  52. $repo = $this->getDoctrine()->getRepository('PackagistWebBundle:Version');
  53. $packages = $repo->getLatestVersionWithPackage();
  54. $feed = $this->buildFeed('Latest Packages', 'Latest packages updated on Packagist.', $packages, $format);
  55. return $this->buildResponse($feed, $format);
  56. }
  57. /**
  58. * @Route(
  59. * "/releases.{format}",
  60. * name="feed_releases",
  61. * requirements={"format"="(rss|atom)"},
  62. * defaults={"format"="rss"}
  63. * )
  64. * @Method({"GET"})
  65. */
  66. public function releasesAction($format)
  67. {
  68. /** @var $repo \Packagist\WebBundle\Entity\PackageRepository */
  69. $repo = $this->getDoctrine()->getRepository('PackagistWebBundle:Package');
  70. $packages = $repo->getNewestPackages();
  71. $feed = $this->buildFeed('Latest Released Packages', 'Latest packages added to Packagist.', $packages, $format);
  72. return $this->buildResponse($feed, $format);
  73. }
  74. /**
  75. * @Route(
  76. * "/vendor.{filter}.{format}",
  77. * name="feed_vendor",
  78. * requirements={"format"="(rss|atom)"},
  79. * defaults={"format"="rss"}
  80. * )
  81. * @Method({"GET"})
  82. */
  83. public function vendorAction($filter, $format)
  84. {
  85. /** @var $repo \Packagist\WebBundle\Entity\PackageRepository */
  86. $repo = $this->getDoctrine()->getRepository('PackagistWebBundle:Package');
  87. $packages = $repo->getLatestPackagesByVendor($filter);
  88. $feed = $this->buildFeed("$filter Packages", "Latest packages updated on Packagist for $filter.", $packages, $format);
  89. return $this->buildResponse($feed, $format);
  90. }
  91. /**
  92. * Builds the desired feed
  93. *
  94. * @param string $title
  95. * @param string $description
  96. * @param array $items
  97. * @param string $format
  98. *
  99. * @return \Zend\Feed\Writer\Feed
  100. */
  101. protected function buildFeed($title, $description, $items, $format)
  102. {
  103. $feed = new \Zend\Feed\Writer\Feed();
  104. $feed->setTitle($title);
  105. $feed->setDescription($description);
  106. $feed->setLink($this->getRequest()->getSchemeAndHttpHost());
  107. $feed->setDateModified(time());
  108. foreach ($items as $item) {
  109. $entry = $feed->createEntry();
  110. $this->populateEntry($entry, $item);
  111. $feed->addEntry($entry);
  112. }
  113. if ($format == 'atom'){
  114. $feed->setFeedLink($this->getRequest()->getUri(), $format);
  115. }
  116. return $feed;
  117. }
  118. /**
  119. * Receives either a Package or a Version and populates a feed entry.
  120. *
  121. * @param \Zend\Feed\Writer\Entry $entry
  122. * @param Package|Version $item
  123. */
  124. protected function populateEntry($entry, $item)
  125. {
  126. if ($item instanceof Package) {
  127. $version = $item->getVersions()->first() ?: new Version();
  128. $this->populatePackageData($entry, $item);
  129. $this->populateVersionData($entry, $version);
  130. }
  131. if ($item instanceof Version) {
  132. $this->populatePackageData($entry, $item->getPackage());
  133. $this->populateVersionData($entry, $item);
  134. }
  135. }
  136. /**
  137. * Populates a feed entry with data coming from Package objects.
  138. *
  139. * @param \Zend\Feed\Writer\Entry $entry
  140. * @param Package $package
  141. */
  142. protected function populatePackageData($entry, $package)
  143. {
  144. $entry->setTitle($package->getPackageName());
  145. $entry->setLink($this->generateUrl('view_package', array('name' => $package->getName()), true));
  146. $entry->setDateModified($package->getUpdatedAt());
  147. $entry->setDateCreated($package->getCreatedAt());
  148. $entry->setDescription($package->getDescription());
  149. }
  150. /**
  151. * Populates a feed entry with data coming from Version objects.
  152. *
  153. * @param \Zend\Feed\Writer\Entry $entry
  154. * @param Version $version
  155. */
  156. protected function populateVersionData($entry, $version)
  157. {
  158. $entry->setTitle($entry->getTitle()." ({$version->getVersion()})");
  159. foreach ($version->getAuthors() as $author) {
  160. /** @var $author \Packagist\WebBundle\Entity\Author */
  161. $entry->addAuthor(array(
  162. 'name' => $author->getName()
  163. ));
  164. }
  165. }
  166. /**
  167. * Creates a HTTP Response and exports feed
  168. *
  169. * @param \Zend\Feed\Writer\Feed $feed
  170. * @param string $format
  171. *
  172. * @return \Symfony\Component\HttpFoundation\Response
  173. */
  174. protected function buildResponse($feed, $format)
  175. {
  176. $content = $feed->export($format);
  177. $etag = md5($content);
  178. $response = new Response($content, 200, array('Content-Type' => "application/$format+xml"));
  179. $response->setEtag($etag);
  180. $response->setSharedMaxAge(3600);
  181. if ($feed->count() > 0) {
  182. $response->setLastModified($feed->getEntry(0)->getDateModified());
  183. }
  184. return $response;
  185. }
  186. }