Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SeoBundle] Added event to populate robots.txt #2937

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 12 additions & 14 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\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

class RobotsController extends Controller
{
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)
{
$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()];
}
}
25 changes: 25 additions & 0 deletions src/Kunstmaan/SeoBundle/Event/RobotsEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Kunstmaan\SeoBundle\Event;

final 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;
}
}
42 changes: 42 additions & 0 deletions src/Kunstmaan/SeoBundle/EventListener/AdminRobotsTxtListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?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);
}
}
32 changes: 32 additions & 0 deletions src/Kunstmaan/SeoBundle/EventListener/FileRobotsTxtListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?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,32 @@
<?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']

33 changes: 33 additions & 0 deletions src/Kunstmaan/SeoBundle/Tests/Event/RobotsEventTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Kunstmaan\SeoBundle\Tests\Event;

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

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,68 @@
<?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 Kunstmaan\SeoBundle\EventListener\AdminRobotsTxtListener;
use PHPUnit\Framework\TestCase;

final 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 Kunstmaan\SeoBundle\EventListener\FileRobotsTxtListener;
use PHPUnit\Framework\TestCase;

final 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,33 @@
<?php

declare(strict_types=1);

namespace Kunstmaan\SeoBundle\Tests\EventListener;

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

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());
}
}