<?php
/*
* This file is part of Sulu.
*
* (c) Sulu GmbH
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Sulu\Bundle\WebsiteBundle\Controller;
use Sulu\Bundle\HttpCacheBundle\Cache\SuluHttpCache;
use Sulu\Bundle\WebsiteBundle\Sitemap\SitemapProviderPoolInterface;
use Sulu\Bundle\WebsiteBundle\Sitemap\XmlSitemapDumperInterface;
use Sulu\Bundle\WebsiteBundle\Sitemap\XmlSitemapRendererInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
/**
* Renders a xml sitemap.
*/
class SitemapController
{
/**
* @var XmlSitemapRendererInterface
*/
private $xmlSitemapRenderer;
/**
* @var SitemapProviderPoolInterface
*/
private $sitemapProviderPool;
/**
* @var XmlSitemapDumperInterface
*/
private $xmlSitemapDumper;
/**
* @var Filesystem
*/
private $filesystem;
/**
* @var UrlGeneratorInterface
*/
private $router;
/**
* @var int
*/
private $cacheLifeTime;
/**
* @var bool
*/
private $debug;
public function __construct(
XmlSitemapRendererInterface $xmlSitemapRenderer,
SitemapProviderPoolInterface $sitemapProviderPool,
XmlSitemapDumperInterface $xmlSitemapDumper,
Filesystem $filesystem,
UrlGeneratorInterface $router,
int $cacheLifeTime,
bool $debug = false
) {
$this->xmlSitemapRenderer = $xmlSitemapRenderer;
$this->sitemapProviderPool = $sitemapProviderPool;
$this->xmlSitemapDumper = $xmlSitemapDumper;
$this->filesystem = $filesystem;
$this->router = $router;
$this->cacheLifeTime = $cacheLifeTime;
$this->debug = $debug;
}
/**
* Render sitemap-index of all available sitemap.xml files.
* If only one provider exists this provider will be rendered directly.
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function indexAction(Request $request)
{
$response = $this->getDumpedIndexResponse($request);
if (!$response) {
$sitemap = $this->xmlSitemapRenderer->renderIndex($request->getScheme(), $request->getHost());
if (!$sitemap) {
$sitemapAlias = null;
foreach ($this->sitemapProviderPool->getProviders() as $sitemapAlias => $provider) {
if ($provider->getMaxPage($request->getScheme(), $request->getHost()) > 0) {
$sitemapAlias = $provider->getAlias();
break;
}
}
if (!$sitemapAlias) {
throw new NotFoundHttpException(\sprintf(
'No sitemaps found for "%s".',
$request->getHttpHost()
));
}
return $this->sitemapPaginatedAction($request, $sitemapAlias, 1);
}
$response = new Response($sitemap);
}
$response->headers->set('Content-Type', 'application/xml');
return $this->setCacheLifetime($response);
}
/**
* Returns index-response if dumped file exists.
*
* @return null|BinaryFileResponse
*/
private function getDumpedIndexResponse(Request $request)
{
$path = $this->xmlSitemapDumper->getIndexDumpPath(
$request->getScheme(),
$request->getHost()
);
if (!$this->filesystem->exists($path)) {
return;
}
return $this->createBinaryFileResponse($path);
}
/**
* Redirect to the first page of a single sitemap provider.
*
* @param string $alias
*
* @return Response
*/
public function sitemapAction($alias)
{
if (!$this->sitemapProviderPool->hasProvider($alias)) {
return new Response(null, 404);
}
return new RedirectResponse(
$this->router->generate(
'sulu_website.paginated_sitemap',
['alias' => $alias, 'page' => 1]
),
301
);
}
/**
* Render a single page for a single sitemap.xml provider.
*
* @param string $alias
* @param int $page
*
* @return Response
*/
public function sitemapPaginatedAction(Request $request, $alias, $page)
{
$response = $this->getDumpedSitemapResponse($request, $alias, $page);
if (!$response) {
$sitemap = $this->xmlSitemapRenderer->renderSitemap(
$alias,
$page,
$request->getScheme(),
$request->getHost()
);
if (!$sitemap) {
return new Response(null, 404);
}
$response = new Response($sitemap);
}
$response->headers->set('Content-Type', 'application/xml');
return $this->setCacheLifetime($response);
}
/**
* Returns index-response if dumped file exists.
*
* @param string $alias
* @param int $page
*
* @return null|BinaryFileResponse
*/
private function getDumpedSitemapResponse(Request $request, $alias, $page)
{
$path = $this->xmlSitemapDumper->getDumpPath(
$request->getScheme(),
$request->getHttpHost(),
$alias,
$page
);
if (!$this->filesystem->exists($path)) {
return;
}
return $this->createBinaryFileResponse($path);
}
/**
* Set cache headers.
*
* @return Response
*/
private function setCacheLifetime(Response $response)
{
$response->headers->set(
SuluHttpCache::HEADER_REVERSE_PROXY_TTL,
$response->getAge() + $this->cacheLifeTime
);
if ($this->debug) {
return $response;
}
return $response->setMaxAge(240)
->setSharedMaxAge(960);
}
/**
* Create a binary file response.
*
* @param string $file
*
* @return BinaryFileResponse
*/
private function createBinaryFileResponse($file)
{
$response = new BinaryFileResponse($file);
$response->headers->addCacheControlDirective('no-store', true);
return $response;
}
}