From 1749ed7c9115b7ec2796422f1df41a88eb3981c8 Mon Sep 17 00:00:00 2001 From: Julien Chanseaume Date: Sat, 3 May 2014 16:48:14 +0200 Subject: [PATCH 1/9] added new route and controller for feeds --- local/modules/Front/Config/front.xml | 9 + .../Front/Controller/FeedController.php | 200 ++++++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 local/modules/Front/Controller/FeedController.php diff --git a/local/modules/Front/Config/front.xml b/local/modules/Front/Config/front.xml index 4f32372a3..0a987eaa2 100644 --- a/local/modules/Front/Config/front.xml +++ b/local/modules/Front/Config/front.xml @@ -200,6 +200,15 @@ + + + Front\Controller\FeedController::generateAction + catalog + + + + + Thelia\Controller\Front\DefaultController::noAction diff --git a/local/modules/Front/Controller/FeedController.php b/local/modules/Front/Controller/FeedController.php new file mode 100644 index 000000000..d9e3a5c5c --- /dev/null +++ b/local/modules/Front/Controller/FeedController.php @@ -0,0 +1,200 @@ + + */ +class FeedController extends BaseFrontController { + + + /** + * Folder name for feeds cache + */ + const FEED_CACHE_DIR = "feeds"; + + /** + * Key prefix for feed cache + */ + const FEED_CACHE_KEY = "feed"; + + + /** + * render the RSS feed + * + * @param $context string The context of the feed : catalog, content. default: catalog + * @param $lang string The lang of the feed : fr_FR, en_US, ... default: default language of the site + * @param $id string The id of the parent element. The id of the main parent category for catalog context. + * The id of the content folder for content context + * @return Response + */ + public function generateAction($context, $lang, $id) + { + + /** @var Request $request */ + $request = $this->getRequest(); + + // context + if ("" === $context){ + $context = "catalog"; + } else if (! in_array($context, array("catalog", "content")) ){ + $this->pageNotFound(); + } + + // the locale : fr, en, + if ("" !== $lang) { + if (! $this->checkLang($lang)){ + $this->pageNotFound(); + } + } else { + try{ + $lang = Lang::getDefaultLanguage(); + $lang = $lang->getLocale(); + } catch (\RuntimeException $ex){ + // @todo generate error page + throw new \RuntimeException("No default language is defined. Please define one."); + } + } + if (null === $lang = LangQuery::create()->findOneByLocale($lang)){ + $this->pageNotFound(); + } + $lang = $lang->getId(); + + // check if element exists and is visible + if ("" !== $id){ + if (false === $this->checkId($context, $id)){ + $this->pageNotFound(); + } + } + + $flush = $request->query->get("flush", ""); + + // check if feed already in cache + $cacheContent = false; + + $cacheDir = $this->getCacheDir(); + $cacheKey = self::FEED_CACHE_KEY . $lang . $context . $id; + $cacheExpire = intval(ConfigQuery::read("feed_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( + "feed", + array( + "_context_" => $context, + "_lang_" => $lang, + "_id_" => $id + ) + ); + // save cache + $cacheDriver->save($cacheKey, $cacheContent, $cacheExpire); + } + + $response = new Response(); + $response->setContent($cacheContent); + $response->headers->set('Content-Type', 'application/rss+xml'); + + return $response; + } + + + /** + * get the cache directory for feeds + * + * @return mixed|string + */ + protected function getCacheDir() + { + $cacheDir = $this->container->getParameter("kernel.cache_dir"); + $cacheDir = rtrim($cacheDir, '/'); + $cacheDir .= '/' . self::FEED_CACHE_DIR . '/'; + + return $cacheDir; + } + + /** + * Check if current user has ADMIN role + * + * @return bool + */ + protected function checkAdmin(){ + return $this->getSecurityContext()->hasAdminUser(); + } + + + /** + * Check if a lang is used + * + * @param $lang The lang code. e.g.: fr + * @return bool true if the language is used, otherwise false + */ + private function checkLang($lang) + { + // load locals + $lang = LangQuery::create() + ->findOneByLocale($lang); + + return (null !== $lang); + } + + + /** + * Ckeck if the element exists and is visible + * + * @param $context string catalog or content + * @param $id string id of the element + * @return bool + */ + private function checkId($context, $id) + { + $ret = false; + if (is_numeric($id)){ + if ("catalog" === $context){ + $cat = CategoryQuery::create()->findPk($id); + $ret = (null !== $cat && $cat->getVisible()); + } else { + $folder = FolderQuery::create()->findPk($id); + $ret = (null !== $folder && $folder->getVisible()); + } + } + return $ret; + } + +} \ No newline at end of file From d094fd496912cb222ff92a771331767f13e5903a Mon Sep 17 00:00:00 2001 From: Julien Chanseaume Date: Sat, 3 May 2014 16:48:42 +0200 Subject: [PATCH 2/9] new template for generating feeds --- templates/frontOffice/default/feed.html | 69 +++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 templates/frontOffice/default/feed.html diff --git a/templates/frontOffice/default/feed.html b/templates/frontOffice/default/feed.html new file mode 100644 index 000000000..f24477796 --- /dev/null +++ b/templates/frontOffice/default/feed.html @@ -0,0 +1,69 @@ + + +{* @todo order item by create date desc *} +{assign var="store_name" value="{config key="store_name"}"} +{loop type="lang" name="lang" id=$_lang_} + {assign var="locale" value="{$LOCALE}"} +{/loop} +{if $_context_ == "catalog"} + + {if $_id_ == "" } + {intl l="Catalog"} | {$store_name} + {url path="/"} + {$store_name} + {$locale|replace:'_':'-'|lower} + {$smarty.now|date_format:'r'} + Thelia 2.0 + {else} + {loop type="category" name="category" id=$_id_ lang=$_lang_ } + {$TITLE} | {$store_name} + {$URL} + {$CHAPO} + {$LOCALE|replace:'_':'-'|lower} + {format_date date=$UPDATE_DATE format="r"} + {$smarty.now|date_format:'r'} + Thelia 2.0 + {/loop} + {/if} + {loop type="product" name="product" category_default=$_id_ lang=$_lang_ order="id_reverse" } + + {$TITLE} + {$URL} + {$CHAPO} + {format_date date=$CREATE_DATE format="r"} + {$URL} + + {/loop} + +{else} + + {if $_id_ == "" } + {intl l="Contents"} | {$store_name} + {url path="/"} + {$store_name} + {$locale|replace:'_':'-'|lower} + {$smarty.now|date_format:'r'} + Thelia 2.0 + {else} + {loop type="folder" name="folder" id=$_id_ lang=$_lang_ } + {$TITLE} | {$store_name} + {$URL} + {$CHAPO} + {$LOCALE|replace:'_':'-'|lower} + {format_date date=$UPDATE_DATE format="r"} + {$smarty.now|date_format:'r'} + Thelia 2.0 + {/loop} + {/if} + {loop type="content" name="content" folder_default=$_id_ lang=$_lang_ } + + {$TITLE} + {$URL} + {$CHAPO} + {format_date date=$CREATE_DATE format="r"} + {$URL} + + {/loop} + +{/if} + From fbc4a87d340cd3e588890ffa15df983beec9f330 Mon Sep 17 00:00:00 2001 From: Julien Chanseaume Date: Sat, 3 May 2014 16:49:53 +0200 Subject: [PATCH 3/9] updated default front theme to integrate RSS feeds --- templates/frontOffice/default/category.html | 5 +++++ templates/frontOffice/default/content.html | 5 +++++ templates/frontOffice/default/layout.tpl | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/templates/frontOffice/default/category.html b/templates/frontOffice/default/category.html index e7fa3116a..6f1b11045 100644 --- a/templates/frontOffice/default/category.html +++ b/templates/frontOffice/default/category.html @@ -18,6 +18,11 @@ {/loop} {/block} +{* Feeds *} +{block name="feeds"} + +{/block} + {* Breadcrumb *} {block name='no-return-functions' append} {$breadcrumbs = []} diff --git a/templates/frontOffice/default/content.html b/templates/frontOffice/default/content.html index 59775fa78..d357487ea 100644 --- a/templates/frontOffice/default/content.html +++ b/templates/frontOffice/default/content.html @@ -18,6 +18,11 @@ {/loop} {/block} +{* Feeds *} +{block name="feeds"} + +{/block} + {* Breadcrumb *} {block name='no-return-functions' append} {$breadcrumbs = []} diff --git a/templates/frontOffice/default/layout.tpl b/templates/frontOffice/default/layout.tpl index ab57fe8da..8a2d06a4c 100644 --- a/templates/frontOffice/default/layout.tpl +++ b/templates/frontOffice/default/layout.tpl @@ -64,6 +64,11 @@ GNU General Public License : http://www.gnu.org/licenses/ {images file='assets/img/favicon.ico'}{/images} {images file='assets/img/favicon.png'}{/images} + {* Feeds *} + + + {block name="feeds"}{/block} + {* HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries *} + + + Front\Controller\FeedController::generateAction + catalog + + + + + Thelia\Controller\Front\DefaultController::noAction diff --git a/local/modules/Front/Controller/FeedController.php b/local/modules/Front/Controller/FeedController.php new file mode 100644 index 000000000..d9e3a5c5c --- /dev/null +++ b/local/modules/Front/Controller/FeedController.php @@ -0,0 +1,200 @@ + + */ +class FeedController extends BaseFrontController { + + + /** + * Folder name for feeds cache + */ + const FEED_CACHE_DIR = "feeds"; + + /** + * Key prefix for feed cache + */ + const FEED_CACHE_KEY = "feed"; + + + /** + * render the RSS feed + * + * @param $context string The context of the feed : catalog, content. default: catalog + * @param $lang string The lang of the feed : fr_FR, en_US, ... default: default language of the site + * @param $id string The id of the parent element. The id of the main parent category for catalog context. + * The id of the content folder for content context + * @return Response + */ + public function generateAction($context, $lang, $id) + { + + /** @var Request $request */ + $request = $this->getRequest(); + + // context + if ("" === $context){ + $context = "catalog"; + } else if (! in_array($context, array("catalog", "content")) ){ + $this->pageNotFound(); + } + + // the locale : fr, en, + if ("" !== $lang) { + if (! $this->checkLang($lang)){ + $this->pageNotFound(); + } + } else { + try{ + $lang = Lang::getDefaultLanguage(); + $lang = $lang->getLocale(); + } catch (\RuntimeException $ex){ + // @todo generate error page + throw new \RuntimeException("No default language is defined. Please define one."); + } + } + if (null === $lang = LangQuery::create()->findOneByLocale($lang)){ + $this->pageNotFound(); + } + $lang = $lang->getId(); + + // check if element exists and is visible + if ("" !== $id){ + if (false === $this->checkId($context, $id)){ + $this->pageNotFound(); + } + } + + $flush = $request->query->get("flush", ""); + + // check if feed already in cache + $cacheContent = false; + + $cacheDir = $this->getCacheDir(); + $cacheKey = self::FEED_CACHE_KEY . $lang . $context . $id; + $cacheExpire = intval(ConfigQuery::read("feed_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( + "feed", + array( + "_context_" => $context, + "_lang_" => $lang, + "_id_" => $id + ) + ); + // save cache + $cacheDriver->save($cacheKey, $cacheContent, $cacheExpire); + } + + $response = new Response(); + $response->setContent($cacheContent); + $response->headers->set('Content-Type', 'application/rss+xml'); + + return $response; + } + + + /** + * get the cache directory for feeds + * + * @return mixed|string + */ + protected function getCacheDir() + { + $cacheDir = $this->container->getParameter("kernel.cache_dir"); + $cacheDir = rtrim($cacheDir, '/'); + $cacheDir .= '/' . self::FEED_CACHE_DIR . '/'; + + return $cacheDir; + } + + /** + * Check if current user has ADMIN role + * + * @return bool + */ + protected function checkAdmin(){ + return $this->getSecurityContext()->hasAdminUser(); + } + + + /** + * Check if a lang is used + * + * @param $lang The lang code. e.g.: fr + * @return bool true if the language is used, otherwise false + */ + private function checkLang($lang) + { + // load locals + $lang = LangQuery::create() + ->findOneByLocale($lang); + + return (null !== $lang); + } + + + /** + * Ckeck if the element exists and is visible + * + * @param $context string catalog or content + * @param $id string id of the element + * @return bool + */ + private function checkId($context, $id) + { + $ret = false; + if (is_numeric($id)){ + if ("catalog" === $context){ + $cat = CategoryQuery::create()->findPk($id); + $ret = (null !== $cat && $cat->getVisible()); + } else { + $folder = FolderQuery::create()->findPk($id); + $ret = (null !== $folder && $folder->getVisible()); + } + } + return $ret; + } + +} \ No newline at end of file From 92a7404a3bbb9420cead2a694c302b662c57ca2b Mon Sep 17 00:00:00 2001 From: Julien Chanseaume Date: Sat, 3 May 2014 16:48:42 +0200 Subject: [PATCH 5/9] new template for generating feeds --- templates/frontOffice/default/feed.html | 69 +++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 templates/frontOffice/default/feed.html diff --git a/templates/frontOffice/default/feed.html b/templates/frontOffice/default/feed.html new file mode 100644 index 000000000..f24477796 --- /dev/null +++ b/templates/frontOffice/default/feed.html @@ -0,0 +1,69 @@ + + +{* @todo order item by create date desc *} +{assign var="store_name" value="{config key="store_name"}"} +{loop type="lang" name="lang" id=$_lang_} + {assign var="locale" value="{$LOCALE}"} +{/loop} +{if $_context_ == "catalog"} + + {if $_id_ == "" } + {intl l="Catalog"} | {$store_name} + {url path="/"} + {$store_name} + {$locale|replace:'_':'-'|lower} + {$smarty.now|date_format:'r'} + Thelia 2.0 + {else} + {loop type="category" name="category" id=$_id_ lang=$_lang_ } + {$TITLE} | {$store_name} + {$URL} + {$CHAPO} + {$LOCALE|replace:'_':'-'|lower} + {format_date date=$UPDATE_DATE format="r"} + {$smarty.now|date_format:'r'} + Thelia 2.0 + {/loop} + {/if} + {loop type="product" name="product" category_default=$_id_ lang=$_lang_ order="id_reverse" } + + {$TITLE} + {$URL} + {$CHAPO} + {format_date date=$CREATE_DATE format="r"} + {$URL} + + {/loop} + +{else} + + {if $_id_ == "" } + {intl l="Contents"} | {$store_name} + {url path="/"} + {$store_name} + {$locale|replace:'_':'-'|lower} + {$smarty.now|date_format:'r'} + Thelia 2.0 + {else} + {loop type="folder" name="folder" id=$_id_ lang=$_lang_ } + {$TITLE} | {$store_name} + {$URL} + {$CHAPO} + {$LOCALE|replace:'_':'-'|lower} + {format_date date=$UPDATE_DATE format="r"} + {$smarty.now|date_format:'r'} + Thelia 2.0 + {/loop} + {/if} + {loop type="content" name="content" folder_default=$_id_ lang=$_lang_ } + + {$TITLE} + {$URL} + {$CHAPO} + {format_date date=$CREATE_DATE format="r"} + {$URL} + + {/loop} + +{/if} + From 6e0e6dddd2836fd38457d6270cf8f38cbf56b7e4 Mon Sep 17 00:00:00 2001 From: Julien Chanseaume Date: Sat, 3 May 2014 16:49:53 +0200 Subject: [PATCH 6/9] updated default front theme to integrate RSS feeds --- templates/frontOffice/default/category.html | 5 +++++ templates/frontOffice/default/content.html | 5 +++++ templates/frontOffice/default/layout.tpl | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/templates/frontOffice/default/category.html b/templates/frontOffice/default/category.html index e7fa3116a..6f1b11045 100644 --- a/templates/frontOffice/default/category.html +++ b/templates/frontOffice/default/category.html @@ -18,6 +18,11 @@ {/loop} {/block} +{* Feeds *} +{block name="feeds"} + +{/block} + {* Breadcrumb *} {block name='no-return-functions' append} {$breadcrumbs = []} diff --git a/templates/frontOffice/default/content.html b/templates/frontOffice/default/content.html index 59775fa78..d357487ea 100644 --- a/templates/frontOffice/default/content.html +++ b/templates/frontOffice/default/content.html @@ -18,6 +18,11 @@ {/loop} {/block} +{* Feeds *} +{block name="feeds"} + +{/block} + {* Breadcrumb *} {block name='no-return-functions' append} {$breadcrumbs = []} diff --git a/templates/frontOffice/default/layout.tpl b/templates/frontOffice/default/layout.tpl index ab57fe8da..8a2d06a4c 100644 --- a/templates/frontOffice/default/layout.tpl +++ b/templates/frontOffice/default/layout.tpl @@ -64,6 +64,11 @@ GNU General Public License : http://www.gnu.org/licenses/ {images file='assets/img/favicon.ico'}{/images} {images file='assets/img/favicon.png'}{/images} + {* Feeds *} + + + {block name="feeds"}{/block} + {* HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries *}