Skip to content

Commit

Permalink
[SeoBundle] Added event to populate robots.txt
Browse files Browse the repository at this point in the history
  • Loading branch information
Patrick Berenschot committed Sep 9, 2021
1 parent d5d7cf1 commit 00daad2
Show file tree
Hide file tree
Showing 10 changed files with 339 additions and 17 deletions.
32 changes: 15 additions & 17 deletions src/Kunstmaan/SeoBundle/Controller/RobotsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,34 @@

namespace Kunstmaan\SeoBundle\Controller;

use Kunstmaan\SeoBundle\Entity\Robots;
use Kunstmaan\SeoBundle\Event\RobotsEvent;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

class RobotsController extends Controller
final class RobotsController extends AbstractController
{
private $dispatcher;

public function __construct(EventDispatcherInterface $dispatcher)
{
$this->dispatcher = $dispatcher;
}

/**
* Generates the robots.txt content when available in the database and falls back to normal robots.txt if exists
*
* @Route(path="/robots.txt", name="KunstmaanSeoBundle_robots", defaults={"_format": "txt"})
* @Template(template="@KunstmaanSeo/Admin/Robots/index.html.twig")
*
* @return array
*/
public function indexAction(Request $request)
public function __invoke(Request $request)
{
$entity = $this->getDoctrine()->getRepository(Robots::class)->findOneBy([]);
$robots = $this->getParameter('robots_default');
$event = new RobotsEvent();

if ($entity && $entity->getRobotsTxt()) {
$robots = $entity->getRobotsTxt();
} else {
$file = $request->getBasePath() . 'robots.txt';
if (file_exists($file)) {
$robots = file_get_contents($file);
}
}
$event = $this->dispatcher->dispatch($event);

return ['robots' => $robots];
return ['robots' => $event->getContent()];
}
}
24 changes: 24 additions & 0 deletions src/Kunstmaan/SeoBundle/Event/RobotsEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);

namespace Kunstmaan\SeoBundle\Event;

class RobotsEvent
{
private $content;

public function __construct(string $content = "")
{
$this->content = $content;
}

public function setContent(string $content): void
{
$this->content = $content;
}

public function getContent(): string
{
return $this->content;
}
}
41 changes: 41 additions & 0 deletions src/Kunstmaan/SeoBundle/EventListener/AdminRobotsTxtListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);

namespace Kunstmaan\SeoBundle\EventListener;

use Doctrine\Persistence\ObjectRepository;
use Kunstmaan\SeoBundle\Entity\Robots;
use Kunstmaan\SeoBundle\Event\RobotsEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

final class AdminRobotsTxtListener implements EventSubscriberInterface
{
private $repository;

public function __construct(ObjectRepository $repository)
{
$this->repository = $repository;
}

public static function getSubscribedEvents(): array
{
return [
RobotsEvent::class => ["__invoke", 100]
];
}

public function __invoke(RobotsEvent $event): void
{
$entity = $this->repository->findOneBy([]);
if (!$entity instanceof Robots) {
return;
}

$content = $entity->getRobotsTxt();
if ($content === null) {
return;
}

$event->setContent($content);
}
}
31 changes: 31 additions & 0 deletions src/Kunstmaan/SeoBundle/EventListener/FileRobotsTxtListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);

namespace Kunstmaan\SeoBundle\EventListener;

use Kunstmaan\SeoBundle\Event\RobotsEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

final class FileRobotsTxtListener implements EventSubscriberInterface
{
private $path;

public function __construct(string $path)
{
$this->path = $path;
}

public static function getSubscribedEvents(): array
{
return [
RobotsEvent::class => ["__invoke", 0]
];
}

public function __invoke(RobotsEvent $event): void
{
if (empty($event->getContent()) && file_exists($this->path)) {
$event->setContent(file_get_contents($this->path));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);

namespace Kunstmaan\SeoBundle\EventListener;

use Kunstmaan\SeoBundle\Event\RobotsEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

final class ParameterRobotsTxtListener implements EventSubscriberInterface
{
private $fallback;

public function __construct(string $fallback)
{
$this->fallback = $fallback;
}

public static function getSubscribedEvents(): array
{
return [
RobotsEvent::class => ["__invoke", -100]
];
}

public function __invoke(RobotsEvent $event): void
{
if (empty($event->getContent())) {
$event->setContent($this->fallback);
}
}
}
23 changes: 23 additions & 0 deletions src/Kunstmaan/SeoBundle/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,26 @@ services:
arguments: ['@security.authorization_checker']
tags:
- { name: 'kunstmaan_admin.menu.adaptor' }

kunstmaanseobundle.repository.robots:
class: Doctrine\ORM\EntityRepository
factory: ["@doctrine.orm.entity_manager", getRepository]
arguments: ['Kunstmaan\SeoBundle\Entity\Robots']

Kunstmaan\SeoBundle\EventListener\AdminRobotsTxtListener:
autoconfigure: true
arguments:
$repository: '@kunstmaanseobundle.repository.robots'

Kunstmaan\SeoBundle\EventListener\FileRobotsTxtListener:
autoconfigure: true
arguments: ["robots.txt", '@request_stack']

Kunstmaan\SeoBundle\EventListener\ParameterRobotsTxtListener:
autoconfigure: true
arguments: ['%robots_default%']

Kunstmaan\SeoBundle\Controller\RobotsController:
autowire: true
tags: ['controller.service_arguments']

32 changes: 32 additions & 0 deletions src/Kunstmaan/SeoBundle/Tests/Event/RobotsEventTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);

namespace Kunstmaan\SeoBundle\Tests\Event;

use PHPUnit\Framework\TestCase;
use Kunstmaan\SeoBundle\Event\RobotsEvent;

class RobotsEventTest extends TestCase
{
public function testShouldAllowSettingContext(): void
{
$initialContent = "Current content";
$object = new RobotsEvent($initialContent);

$result = $object->getContent();
$this->assertEquals($initialContent, $result);

$newContent = "$result\nAdded";
$object->setContent($newContent);

$this->assertEquals($newContent, $object->getContent());
}

public function testShouldDefaultToEmptyContent(): void
{
$object = new RobotsEvent();

$result = $object->getContent();
$this->assertEquals("", $result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php
declare(strict_types=1);

namespace Kunstmaan\SeoBundle\Tests\EventListener;

use Doctrine\ORM\EntityRepository;
use Kunstmaan\SeoBundle\Entity\Robots;
use Kunstmaan\SeoBundle\Event\RobotsEvent;
use PHPUnit\Framework\TestCase;
use Kunstmaan\SeoBundle\EventListener\AdminRobotsTxtListener;

class AdminRobotsTxtListenerTest extends TestCase
{
private $repoMock;
private const CONTENT = "User-agent: *
Allow: /";

public function testShouldSetContentWhenEntityExists()
{
$filled = new Robots();
$filled->setRobotsTxt(self::CONTENT);

$this->repoMock = $this->createMock(EntityRepository::class);
$this->repoMock->expects($this->any())
->method("findOneBy")
->with([])
->willReturn($filled);

$event = new RobotsEvent();
$listener = new AdminRobotsTxtListener($this->repoMock);
$listener->__invoke($event);

$this->assertEquals(self::CONTENT, $event->getContent());
}

public function testShouldDoNothingWhenEntityMissing()
{
$this->repoMock = $this->createMock(EntityRepository::class);
$this->repoMock->expects($this->any())
->method("findOneBy")
->with([])
->willReturn(null);

$event = new RobotsEvent("untouched");
$listener = new AdminRobotsTxtListener($this->repoMock);
$listener->__invoke($event);

$this->assertEquals("untouched", $event->getContent());
}

public function testShouldDoNothingWhenEntityEmpty()
{
$empty = new Robots();

$this->repoMock = $this->createMock(EntityRepository::class);
$this->repoMock->expects($this->any())
->method("findOneBy")
->with([])
->willReturn($empty);

$event = new RobotsEvent("untouched");
$listener = new AdminRobotsTxtListener($this->repoMock);
$listener->__invoke($event);

$this->assertEquals("untouched", $event->getContent());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);

namespace Kunstmaan\SeoBundle\Tests\EventListener;

use Kunstmaan\SeoBundle\Event\RobotsEvent;
use PHPUnit\Framework\TestCase;
use Kunstmaan\SeoBundle\EventListener\FileRobotsTxtListener;
use Symfony\Component\HttpFoundation\RequestStack;

class FileRobotsTxtListenerTest extends TestCase
{
private const CONTENT = "User-agent: *
Allow: /";

public function testShouldDoNothingWhenFilled(): void
{
$event = new RobotsEvent();
$event->setContent(self::CONTENT);
$listener = new FileRobotsTxtListener(__FILE__);
$listener->__invoke($event);

$this->assertEquals(self::CONTENT, $event->getContent());
}

public function testShouldSetContentFromFileWhenEmpty(): void
{
$event = new RobotsEvent();
$listener = new FileRobotsTxtListener(__FILE__);
$listener->__invoke($event);

$this->assertEquals(file_get_contents(__FILE__), $event->getContent());
}

public function testShouldDoNothingWhenFileDoesNotExists(): void {

$event = new RobotsEvent();
$listener = new FileRobotsTxtListener("/some/none/existing/file");
$listener->__invoke($event);

$this->assertEquals("", $event->getContent());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);

namespace Kunstmaan\SeoBundle\Tests\EventListener;

use Kunstmaan\SeoBundle\Event\RobotsEvent;
use PHPUnit\Framework\TestCase;
use Kunstmaan\SeoBundle\EventListener\ParameterRobotsTxtListener;

class ParameterRobotsTxtListenerTest extends TestCase
{
private const CONTENT = "User-agent: *
Allow: /";

public function testShouldSetContentWhenEmpty()
{
$event = new RobotsEvent();
$listener = new ParameterRobotsTxtListener("fallback content");
$listener->__invoke($event);

$this->assertEquals("fallback content", $event->getContent());
}

public function testShouldSetDoNothingWhenFilled()
{
$event = new RobotsEvent(self::CONTENT);
$listener = new ParameterRobotsTxtListener("fallback content");
$listener->__invoke($event);

$this->assertEquals(self::CONTENT, $event->getContent());
}
}

0 comments on commit 00daad2

Please sign in to comment.