Merge pull request #357 from bibich/sitemap

Sitemap functionality
This commit is contained in:
Manuel Raynaud
2014-04-30 09:25:54 +02:00
5 changed files with 214 additions and 1 deletions

View File

@@ -194,6 +194,12 @@
</route>
<!-- end newsletter management -->
<!-- sitemap generator -->
<route id="sitemap.process" path="/sitemap">
<default key="_controller">Front\Controller\SitemapController::generateAction</default>
</route>
<!-- end sitemap generator -->
<!-- Default Route -->
<route id="default" path="/{_view}">
<default key="_controller">Thelia\Controller\Front\DefaultController::noAction</default>

View File

@@ -0,0 +1,157 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace Front\Controller;
use Thelia\Controller\Front\BaseFrontController;
use Thelia\Core\HttpFoundation\Request;
use Thelia\Core\HttpFoundation\Response;
use Thelia\Log\Tlog;
use Thelia\Model\ConfigQuery;
/**
* Controller uses to generate sitemap.xml
*
* A default cache of 2 hours is used to avoid attack. You can flush cache if you have `ADMIN` role and pass flush=1 in
* query parameter.
*
* @package Front\Controller
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
*/
class SitemapController extends BaseFrontController {
/**
* Folder name for sitemap cache
*/
const SITEMAP_DIR = "sitemap";
/**
* Folder name for sitemap cache
*/
const SITEMAP_FILE = "sitemap";
/**
* @return Response
*/
public function generateAction()
{
/** @var Request $request */
$request = $this->getRequest();
$flush = $request->query->get("flush", "");
$expire = ConfigQuery::read("sitemap_ttl", '7200');
// check if sitemap already in cache
$cacheDir = $this->getCacheDir();
$cacheFileURL = $cacheDir . self::SITEMAP_FILE . '.xml';
$expire = intval($expire) ?: 7200;
$cacheContent = null;
if (!($this->checkAdmin() && "" !== $flush)){
try {
$cacheContent = $this->getCache($cacheFileURL, $expire);
} catch (\RuntimeException $ex) {
// Problem loading cache, permission errors ?
Tlog::getInstance()->addAlert($ex->getMessage());
}
}
if (null === $cacheContent){
// render the view
$cacheContent = $this->renderRaw("sitemap");
// save cache
try {
$this->setCache($cacheFileURL, $cacheContent);
} catch (\RuntimeException $ex) {
// Problem loading cache, permission errors ?
Tlog::getInstance()->addAlert($ex->getMessage());
}
}
$response = new Response();
$response->setContent($cacheContent);
$response->headers->set('Content-Type', 'application/xml');
return $response;
}
/**
* Check if current user has ADMIN role
*
* @return bool
*/
protected function checkAdmin(){
return $this->getSecurityContext()->isGranted(array("ADMIN"), array(), array(), array());
}
/**
* Get the content of the file if it exists and not expired?
*
* @param $fileURL path to the file
* @param $expire TTL for the file
* @return null|string The content of the file if it exists and not expired
* @throws \RuntimeException
*/
protected function getCache($fileURL, $expire)
{
$content = null;
if (is_file($fileURL)){
$mtime = filemtime($fileURL);
if ($mtime + $expire < time()){
if (! @unlink($fileURL)){
throw new \RuntimeException(sprintf("Failed to remove %s file in cache directory", $fileURL));
}
} else {
$content = file_get_contents($fileURL);
}
}
return $content;
}
/**
* Save content in the file specified by `$fileURL`
*
* @param $fileURL the path to the file
* @param $content the content of the file
* @throws \RuntimeException
*/
protected function setCache($fileURL, $content)
{
if (! @file_put_contents($fileURL, $content)){
throw new \RuntimeException(sprintf("Failed to save %s file in cache directory", $fileURL));
}
}
/**
* Retrieve the cache dir used for sitemaps
*
* @return string the path to the cache dir
* @throws \RuntimeException
*/
protected function getCacheDir()
{
$cacheDir = $this->container->getParameter("kernel.cache_dir");
$cacheDir = rtrim($cacheDir, '/');
$cacheDir .= '/' . self::SITEMAP_DIR . '/';
if (! is_dir($cacheDir)){
if (! @mkdir($cacheDir, 0777, true)) {
throw new \RuntimeException(sprintf("Failed to create %s dir in cache directory", self::SITEMAP_DIR));
}
}
return $cacheDir;
}
}

View File

@@ -45,7 +45,8 @@ INSERT INTO `config` (`name`, `value`, `secured`, `hidden`, `created_at`, `updat
('thelia_release_version','1', 1, 1, NOW(), NOW()),
('thelia_extra_version','', 1, 1, NOW(), NOW()),
('front_cart_country_cookie_name','fcccn', 1, 1, NOW(), NOW()),
('front_cart_country_cookie_expires','2592000', 1, 1, NOW(), NOW());
('front_cart_country_cookie_expires','2592000', 1, 1, NOW(), NOW()),
('sitemap_ttl','7200', 1, 1, NOW(), NOW());
INSERT INTO `config_i18n` (`id`, `locale`, `title`, `description`, `chapo`, `postscriptum`) VALUES

View File

@@ -10,6 +10,8 @@ INSERT INTO `config` (`name`, `value`, `secured`, `hidden`, `created_at`, `updat
('front_cart_country_cookie_name','fcccn', 1, 1, NOW(), NOW());
INSERT INTO `config` (`name`, `value`, `secured`, `hidden`, `created_at`, `updated_at`) VALUES
('front_cart_country_cookie_expires','2592000', 1, 1, NOW(), NOW());
INSERT INTO `config` (`name`, `value`, `secured`, `hidden`, `created_at`, `updated_at`) VALUES
('sitemap_ttl','7200', 1, 1, NOW(), NOW());
ALTER TABLE `module` ADD INDEX `idx_module_activate` (`activate`);

View File

@@ -0,0 +1,47 @@
<?xml version="1.0"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>{url path="/"}</loc>
</url>
<!-- categories -->
{loop type="lang" name="category_lang"}
{loop type="category" name="category" lang="$ID"}
<url>
<loc>{$URL}</loc>
<lastmod>{format_date date=$UPDATE_DATE format="c"}</lastmod>
{*
You can also set priority and changefreq
<priority>0.8</priority>
<changefreq>weekly</changefreq>
*}
</url>
{/loop}
{/loop}
<!-- products -->
{loop type="lang" name="product_lang"}
{loop type="product" name="product" lang="$ID"}
<url>
<loc>{$URL}</loc>
<lastmod>{format_date date=$UPDATE_DATE format="c"}</lastmod>
</url>
{/loop}
{/loop}
<!-- folders -->
{loop type="lang" name="folder_lang"}
{loop type="folder" name="folder" lang="$ID"}
<url>
<loc>{$URL}</loc>
<lastmod>{format_date date=$UPDATE_DATE format="c"}</lastmod>
</url>
{/loop}
{/loop}
<!-- contents -->
{loop type="lang" name="content_lang"}
{loop type="content" name="content" lang="$ID"}
<url>
<loc>{$URL}</loc>
<lastmod>{format_date date=$UPDATE_DATE format="c"}</lastmod>
</url>
{/loop}
{/loop}
</urlset>