Add endpoint for getting a feed via it's URL, as well as caching the result
This commit is contained in:
parent
70e78bcf42
commit
78ed53d529
@ -26,6 +26,22 @@ class FeedController
|
|||||||
return $this->view->render($response, 'index.twig.html', ['feeds' => $feeds]);
|
return $this->view->render($response, 'index.twig.html', ['feeds' => $feeds]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get_feed(ServerRequestInterface $request, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
$this->logger->info("FeedController::get_feed() called");
|
||||||
|
$feed = $this->feedRepository->find($request->getAttribute('id'));
|
||||||
|
$filtered = $feed->get_filtered_feed();
|
||||||
|
|
||||||
|
$body = $response->getBody();
|
||||||
|
$body->write($filtered->asXML());
|
||||||
|
|
||||||
|
$this->feedRepository->save($feed);
|
||||||
|
|
||||||
|
return $response->withHeader('Content-Type', 'application/rss+xml')
|
||||||
|
->withBody($body)
|
||||||
|
->withStatus(200);
|
||||||
|
}
|
||||||
|
|
||||||
public function create(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
|
public function create(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
|
||||||
{
|
{
|
||||||
$this->logger->info("FeedController::create() called");
|
$this->logger->info("FeedController::create() called");
|
||||||
|
@ -45,10 +45,15 @@ class Feed
|
|||||||
#[ORM\Column(type: XMLElement::NAME, nullable: true)]
|
#[ORM\Column(type: XMLElement::NAME, nullable: true)]
|
||||||
public SimpleXMLElement|null $filteredFeed;
|
public SimpleXMLElement|null $filteredFeed;
|
||||||
|
|
||||||
|
#[ORM\Column(type: Types::DATETIMETZ_IMMUTABLE, nullable: true)]
|
||||||
|
public \DateTimeInterface|null $lastFetched;
|
||||||
|
|
||||||
public function fetch(): void
|
public function fetch(): void
|
||||||
{
|
{
|
||||||
if (Robots::allowed($this->url)) {
|
if (Robots::allowed($this->url)) {
|
||||||
$this->remoteFeed = simplexml_load_file($this->url);
|
$this->remoteFeed = simplexml_load_file($this->url);
|
||||||
|
$this->filter();
|
||||||
|
$this->lastFetched = new \DateTimeImmutable();
|
||||||
} else {
|
} else {
|
||||||
throw new \Exception("Robots.txt disallows fetching this feed");
|
throw new \Exception("Robots.txt disallows fetching this feed");
|
||||||
}
|
}
|
||||||
@ -65,10 +70,6 @@ class Feed
|
|||||||
|
|
||||||
public function filter() : void
|
public function filter() : void
|
||||||
{
|
{
|
||||||
if ($this->remoteFeed === null) {
|
|
||||||
$this->fetch();
|
|
||||||
}
|
|
||||||
|
|
||||||
$dom = dom_import_simplexml($this->remoteFeed);
|
$dom = dom_import_simplexml($this->remoteFeed);
|
||||||
$doc = $dom->ownerDocument;
|
$doc = $dom->ownerDocument;
|
||||||
|
|
||||||
@ -78,11 +79,27 @@ class Feed
|
|||||||
$xpath_query = '//item[' . $filter_queries . ']';
|
$xpath_query = '//item[' . $filter_queries . ']';
|
||||||
|
|
||||||
$to_remove = $xpath->query($xpath_query);
|
$to_remove = $xpath->query($xpath_query);
|
||||||
echo "Removing " . $to_remove->length . " items\n";
|
|
||||||
foreach ($to_remove as $item) {
|
foreach ($to_remove as $item) {
|
||||||
$item->parentNode->removeChild($item);
|
$item->parentNode->removeChild($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$title = $xpath->query('//channel/title');
|
||||||
|
$title->item(0)->nodeValue = $this->title;
|
||||||
|
|
||||||
$this->filteredFeed = simplexml_import_dom($dom);
|
$this->filteredFeed = simplexml_import_dom($dom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get_filtered_feed(): SimpleXMLElement
|
||||||
|
{
|
||||||
|
if (!$this->lastFetched || $this->lastFetched < new \DateTimeImmutable('-1 hour')) {
|
||||||
|
$this->fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->filteredFeed === null) {
|
||||||
|
$this->filter();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->filteredFeed;
|
||||||
|
}
|
||||||
}
|
}
|
@ -15,4 +15,10 @@ class FeedRepository extends EntityRepository
|
|||||||
{
|
{
|
||||||
parent::__construct($em, $em->getClassMetadata(Feed::class));
|
parent::__construct($em, $em->getClassMetadata(Feed::class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function save(Feed $feed): void
|
||||||
|
{
|
||||||
|
$this->_em->persist($feed);
|
||||||
|
$this->_em->flush();
|
||||||
|
}
|
||||||
}
|
}
|
@ -44,36 +44,19 @@ class TestFeed extends Command
|
|||||||
$url = $input->getArgument("url");
|
$url = $input->getArgument("url");
|
||||||
$title = $input->getArgument("title");
|
$title = $input->getArgument("title");
|
||||||
|
|
||||||
// $output->writeln("Setting up a new feed for: $url");
|
$output->writeln("Setting up a new feed for: $url");
|
||||||
//
|
|
||||||
// $feed = new Feed();
|
|
||||||
// $feed->url = $url;
|
|
||||||
// $feed->title = $title;
|
|
||||||
// $feed->fetch();
|
|
||||||
// $feed->feedFilters = new ArrayCollection();
|
|
||||||
// $feed->feedFilters->add( new FeedFilter(FilterTarget::TITLE, FilterType::INCLUDE, "[No Ads]", $feed));
|
|
||||||
//
|
|
||||||
// $this->em->persist($feed);
|
|
||||||
// $this->em->flush();
|
|
||||||
//
|
|
||||||
// $cnt = $this->feedRepository->count([]);
|
|
||||||
// $output->writeln("Feed count: $cnt");
|
|
||||||
|
|
||||||
$saved_feed = $this->feedRepository->findOneBy(['url' => $url, 'title' => $title]);
|
$feed = new Feed();
|
||||||
$output->writeln("Feed title: " . $saved_feed->title);
|
$feed->url = $url;
|
||||||
|
$feed->title = $title;
|
||||||
|
|
||||||
$s2_filter = new FeedFilter(FilterTarget::TITLE, FilterType::EXCLUDE, "S2", $saved_feed);
|
$feed->feedFilters = new ArrayCollection();
|
||||||
$this->em->persist($s2_filter);
|
$feed->feedFilters->add( new FeedFilter(FilterTarget::TITLE, FilterType::INCLUDE, "[No Ads]", $feed));
|
||||||
|
$feed->feedFilters->add( new FeedFilter(FilterTarget::TITLE, FilterType::EXCLUDE, "S2", $feed));
|
||||||
|
|
||||||
|
$this->em->persist($feed);
|
||||||
$this->em->flush();
|
$this->em->flush();
|
||||||
|
|
||||||
$saved_feed = $this->feedRepository->findOneBy(['url' => $url, 'title' => $title]);
|
|
||||||
$saved_feed->filter();
|
|
||||||
|
|
||||||
$this->em->persist($saved_feed);
|
|
||||||
$this->em->flush();
|
|
||||||
|
|
||||||
$output->writeln("Filtered feed: " . $saved_feed->filteredFeed->asXML('feed_filtered.xml'));
|
|
||||||
|
|
||||||
return Command::SUCCESS;
|
return Command::SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,6 +23,8 @@ $app->get("/", [SampleController::class, 'get']);
|
|||||||
|
|
||||||
$app->get('/feed', [FeedController::class, 'get']);
|
$app->get('/feed', [FeedController::class, 'get']);
|
||||||
|
|
||||||
|
$app->get('/feed/{id}', [FeedController::class, 'get_feed']);
|
||||||
|
|
||||||
$app->addErrorMiddleware(true, true, true);
|
$app->addErrorMiddleware(true, true, true);
|
||||||
|
|
||||||
$app->run();
|
$app->run();
|
Loading…
Reference in New Issue
Block a user