diff --git a/composer.json b/composer.json index 75194a926..37f3a0b15 100644 --- a/composer.json +++ b/composer.json @@ -1,40 +1,36 @@ { - "name" : "thelia/thelia", - "description" : "Thelia is an ecommerce CMS.", - "license" : "LGPL-3.0+", - "homepage" : "http://thelia.net/", - "support" : { - "forum" : "http://thelia.net/forum", - "wiki" : "http://doc.thelia.net" + "name": "thelia/thelia", + "description": "Thelia is an ecommerce CMS.", + "license": "LGPL-3.0+", + "homepage": "http://thelia.net/", + "support": { + "forum": "http://thelia.net/forum", + "wiki": "http://doc.thelia.net" }, - "require":{ + "require": { "php": ">=5.4", "ircmaxell/password-compat": "1.0.*", "propel/propel": "dev-master", - "psr/log" : "1.0", + "psr/log": "1.0", "symfony/class-loader": "2.2.*", - "symfony/config" : "2.2.*", - "symfony/console" : "2.2.*", - "symfony/dependency-injection" : "2.2.*", - "symfony/event-dispatcher" : "2.2.*", - "symfony/http-kernel" : "2.2.*", - "symfony/routing" : "2.2.*", - "symfony/filesystem" : "2.2.*", - "symfony/yaml" : "2.2.*", - "symfony/translation" : "2.2.*", - + "symfony/config": "2.2.*", + "symfony/console": "2.2.*", + "symfony/dependency-injection": "2.2.*", + "symfony/event-dispatcher": "2.2.*", + "symfony/http-kernel": "2.2.*", + "symfony/routing": "2.2.*", + "symfony/filesystem": "2.2.*", + "symfony/yaml": "2.2.*", + "symfony/translation": "2.2.*", "symfony-cmf/routing": "1.0.0", - "symfony/form": "2.2.*", "symfony/validator": "2.3.*", - "smarty/smarty": "v3.1.14", "kriswallsmith/assetic": "1.2.*@dev", "leafo/lessphp": "0.4.*", "ptachoire/cssembed": "1.0.*", - + "doctrine/cache": "v1.3.0", "simplepie/simplepie": "dev-master", - "imagine/imagine": "0.*", "symfony/icu": "1.0", "swiftmailer/swiftmailer": "5.0.*", @@ -42,20 +38,20 @@ "ensepar/html2pdf": "1.0.1", "symfony/finder": "~2.2" }, - "require-dev" : { + "require-dev": { "phpunit/phpunit": "3.7.*", "fzaninotto/faker": "dev-master", "maximebf/debugbar": "dev-master" }, "minimum-stability": "stable", - "config" : { - "vendor-dir" : "core/vendor", - "bin-dir" : "bin" + "config": { + "vendor-dir": "core/vendor", + "bin-dir": "bin" }, "autoload": { "psr-0": { "": "local/modules/", - "Thelia" : "core/lib/" + "Thelia": "core/lib/" } }, "extra": { @@ -79,7 +75,9 @@ "reference": "tags/Smarty_3_1_14/distribution/" }, "autoload": { - "classmap": ["libs/"] + "classmap": [ + "libs/" + ] } } } diff --git a/composer.lock b/composer.lock index 47290ff45..d7da926ba 100644 --- a/composer.lock +++ b/composer.lock @@ -3,8 +3,82 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "5091d03a67414e4ed7aef32a8c737503", + "hash": "d1e1c31ed8e38f2282ab431898cf8b08", "packages": [ + { + "name": "doctrine/cache", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "e16d7adf45664a50fa86f515b6d5e7f670130449" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/e16d7adf45664a50fa86f515b6d5e7f670130449", + "reference": "e16d7adf45664a50fa86f515b6d5e7f670130449", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "phpunit/phpunit": ">=3.7", + "satooshi/php-coveralls": "~0.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Cache\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan H. Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/", + "role": "Creator" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "http://jmsyst.com", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Caching library offering an object-oriented API for many cache backends", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "time": "2013-10-25 19:04:14" + }, { "name": "ensepar/html2pdf", "version": "1.0.1", diff --git a/core/lib/Thelia/Core/Template/Loop/Content.php b/core/lib/Thelia/Core/Template/Loop/Content.php index 1d112df25..377737088 100644 --- a/core/lib/Thelia/Core/Template/Loop/Content.php +++ b/core/lib/Thelia/Core/Template/Loop/Content.php @@ -223,9 +223,6 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface ->set("VISIBLE" , $content->getVisible()) ; - - - $loopResult->addRow($this->findNextPrev($loopResultRow, $content, $defaultFolderId)); } @@ -234,8 +231,8 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface } /** - * @param LoopResultRow $loopResultRow - * @param \Thelia\Model\Content $content + * @param LoopResultRow $loopResultRow + * @param \Thelia\Model\Content $content * @param $defaultFolderId * @return LoopResultRow */ diff --git a/core/lib/Thelia/Form/SeoFieldsTrait.php b/core/lib/Thelia/Form/SeoFieldsTrait.php index d0af736bf..cb64ad6c0 100644 --- a/core/lib/Thelia/Form/SeoFieldsTrait.php +++ b/core/lib/Thelia/Form/SeoFieldsTrait.php @@ -12,7 +12,6 @@ namespace Thelia\Form; -use Symfony\Component\Validator\Constraints\NotBlank; use Thelia\Core\Translation\Translator; /** diff --git a/local/modules/Front/Controller/SitemapController.php b/local/modules/Front/Controller/SitemapController.php index 422d4247f..df339c5bb 100644 --- a/local/modules/Front/Controller/SitemapController.php +++ b/local/modules/Front/Controller/SitemapController.php @@ -13,17 +13,26 @@ namespace Front\Controller; +use Doctrine\Common\Cache\FilesystemCache; use Thelia\Controller\Front\BaseFrontController; use Thelia\Core\HttpFoundation\Request; use Thelia\Core\HttpFoundation\Response; use Thelia\Log\Tlog; use Thelia\Model\ConfigQuery; +use Thelia\Model\LangQuery; /** * 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. + * query string parameter. + * + * You can generate sitemap according to specific language and/or specific context (catalog/content). You have to + * use ```lang``` and ```context``` query string parameters to do so. If a language is not used in website or if the + * context is not supported the page not found is displayed. + * + * {url}/sitemap?lang=fr&context=catalog will generate a sitemap for catalog (categories and products) + * for french language. * * @package Front\Controller * @author Julien Chanséaume @@ -34,12 +43,12 @@ class SitemapController extends BaseFrontController { /** * Folder name for sitemap cache */ - const SITEMAP_DIR = "sitemap"; + const SITEMAP_CACHE_DIR = "sitemap"; /** - * Folder name for sitemap cache + * Key prefix for sitemap cache */ - const SITEMAP_FILE = "sitemap"; + const SITEMAP_CACHE_KEY = "sitemap"; /** * @return Response @@ -49,36 +58,48 @@ class SitemapController extends BaseFrontController { /** @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()); + // the locale : fr, en, + $lang = $request->query->get("lang", ""); + if ("" !== $lang) { + if (! $this->checkLang($lang)){ + $this->pageNotFound(); } } + // specific content : product, category, cms + $context = $request->query->get("context", ""); + if (! in_array($context, array("", "catalog", "content")) ){ + $this->pageNotFound(); + } - if (null === $cacheContent){ + $flush = $request->query->get("flush", ""); + + // check if sitemap already in cache + $cacheContent = false; + + $cacheDir = $this->getCacheDir(); + $cacheKey = self::SITEMAP_CACHE_KEY . $lang . $context; + $cacheExpire = intval(ConfigQuery::read("sitemap_ttl", '7200')) ?: 7200; + + $cacheDriver = new FilesystemCache($cacheDir); + if (!($this->checkAdmin() && "" !== $flush)){ + $cacheContent = $cacheDriver->fetch($cacheKey); + } else { + $cacheDriver->delete($cacheKey); + } + + // if not in cache + if (false === $cacheContent){ // render the view - $cacheContent = $this->renderRaw("sitemap"); - + $cacheContent = $this->renderRaw( + "sitemap", + array( + "_lang_" => $lang, + "_context_" => $context + ) + ); // save cache - try { - $this->setCache($cacheFileURL, $cacheContent); - } catch (\RuntimeException $ex) { - // Problem loading cache, permission errors ? - Tlog::getInstance()->addAlert($ex->getMessage()); - } - + $cacheDriver->save($cacheKey, $cacheContent, $cacheExpire); } $response = new Response(); @@ -88,70 +109,44 @@ class SitemapController extends BaseFrontController { return $response; } + + /** + * get the cache directory for sitemap + * + * @return mixed|string + */ + protected function getCacheDir() + { + $cacheDir = $this->container->getParameter("kernel.cache_dir"); + $cacheDir = rtrim($cacheDir, '/'); + $cacheDir .= '/' . self::SITEMAP_CACHE_DIR . '/'; + + return $cacheDir; + } + /** * Check if current user has ADMIN role * * @return bool */ protected function checkAdmin(){ - return $this->getSecurityContext()->isGranted(array("ADMIN"), array(), array(), array()); + return $this->getSecurityContext()->hasAdminUser(); } - /** - * 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` + * Check if a lang is used * - * @param $fileURL the path to the file - * @param $content the content of the file - * @throws \RuntimeException + * @param $lang The lang code. e.g.: fr + * @return bool true if the language is used, otherwise false */ - protected function setCache($fileURL, $content) + private function checkLang($lang) { - if (! @file_put_contents($fileURL, $content)){ - throw new \RuntimeException(sprintf("Failed to save %s file in cache directory", $fileURL)); - } - } + // load locals + $lang = LangQuery::create() + ->findOneByCode($lang); - /** - * 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; + return (null !== $lang); } } \ No newline at end of file diff --git a/templates/frontOffice/default/sitemap.html b/templates/frontOffice/default/sitemap.html index 75d43920f..f95263eec 100644 --- a/templates/frontOffice/default/sitemap.html +++ b/templates/frontOffice/default/sitemap.html @@ -1,47 +1,71 @@ + - - {url path="/"} - - -{loop type="lang" name="category_lang"} -{loop type="category" name="category" lang="$ID"} - - {$URL} - {format_date date=$UPDATE_DATE format="c"} - {* - You can also set priority and changefreq - 0.8 - weekly - *} - -{/loop} -{/loop} - -{loop type="lang" name="product_lang"} -{loop type="product" name="product" lang="$ID"} - - {$URL} - {format_date date=$UPDATE_DATE format="c"} - -{/loop} -{/loop} - -{loop type="lang" name="folder_lang"} -{loop type="folder" name="folder" lang="$ID"} - - {$URL} - {format_date date=$UPDATE_DATE format="c"} - -{/loop} -{/loop} - -{loop type="lang" name="content_lang"} -{loop type="content" name="content" lang="$ID"} - - {$URL} - {format_date date=$UPDATE_DATE format="c"} - -{/loop} -{/loop} + + {url path="/"} + {* + You can also set priority and changefreq + 0.8 + weekly + *} + + +{if $_context_ == "" || $_context_ == "catalog" } + + + {loop type="lang" name="category_lang"} + {if $_lang_ == "" || $_lang_ == $CODE } + {loop type="category" name="category" lang="$ID"} + + {$URL} + {format_date date=$UPDATE_DATE format="c"} + + {/loop} + {/if} + {/loop} + + + {loop type="lang" name="product_lang"} + {if $_lang_ == "" || $_lang_ == $CODE } + {loop type="product" name="product" lang="$ID"} + + {$URL} + {format_date date=$UPDATE_DATE format="c"} + + {/loop} + {/if} + {/loop} + +{/if} + +{if $_context_ == "" || $_context_ == "content" } + + {loop type="lang" name="folder_lang"} + {if $_lang_ == "" || $_lang_ == $CODE } + {loop type="folder" name="folder" lang="$ID"} + + {$URL} + {format_date date=$UPDATE_DATE format="c"} + + {/loop} + {/if} + {/loop} + + + {loop type="lang" name="content_lang"} + {if $_lang_ == "" || $_lang_ == $CODE } + {loop type="content" name="content" lang="$ID"} + + {$URL} + {format_date date=$UPDATE_DATE format="c"} + + {/loop} + {/if} + {/loop} +{/if} + \ No newline at end of file diff --git a/web/robots.txt b/web/robots.txt index 8f5f570ab..8e180fe20 100644 --- a/web/robots.txt +++ b/web/robots.txt @@ -6,4 +6,4 @@ Disallow: /admin Disallow: /cart Disallow: /404 -#Sitemap: http://www.yourdomain.com/sitemap.xml \ No newline at end of file +#Sitemap: http://www.yourdomain.com/sitemap \ No newline at end of file