Skip to content

Instantly share code, notes, and snippets.

@xymor
Last active August 29, 2015 14:04
Show Gist options
  • Save xymor/56621e11aad2ff203ad8 to your computer and use it in GitHub Desktop.
Save xymor/56621e11aad2ff203ad8 to your computer and use it in GitHub Desktop.
Grails CMS
package commerce.catalog.cms
import grails.util.*
class ComponentTagLib {
def storeService, resourceService, groovyPagesTemplateEngine, cacheUtils, grailsApplication, cookieManager
def section = { attrs ->
def store = storeService.getStore()
if(useCache(store)){
def cacheKey = createCacheKey('section', "${store.id}-${attrs.name}", attrs)
out << cacheUtils.doWithCacheWithTimeout(cacheKey, grailsApplication.config.cacheUtils.componentTimeOut as Integer){
def section = findSection(attrs.name)
if(section){
this.renderComponentsFromSection(section, attrs)
}
}
}else{
def section = findSection(attrs.name)
if(section){
out << this.renderComponentsFromSection(section, attrs)
}
}
}
def component = { attrs ->
def store = storeService.getStore()
if(useCache(store)){
def cacheKey = createCacheKey('component', "${store.id}-${attrs.name}", attrs)
out << cacheUtils.doWithCacheWithTimeout(cacheKey, grailsApplication.config.cacheUtils.componentTimeOut as Integer){
this.renderComponent(ComponentInstance.findByName(attrs.name, [cache: true, readOnly: true]), attrs)
}
}else{
out << this.renderComponent(ComponentInstance.findByName(attrs.name, [cache: true, readOnly: true]), attrs)
}
}
def componentMetaDescription = { attrs ->
def componentInstance = ComponentInstance.findByName(attrs.name, [cache: true, readOnly: true])
if (componentInstance?.description){
out << "<meta name='description' content='${componentInstance?.description}' />"
}
}
def renderPropComponent = { attrs ->
def componentInstance = ComponentInstance.findByIsActiveAndName(true, attrs.name, [cache: true, readOnly: true])
out << componentInstance.props[attrs.prop]
}
def renderGspProp = { attrs ->
def store = storeService.getStore()
if(useCache(store)){
def cacheKey = createCacheKey('gspProp', "${store.id}-${attrs.name}", attrs)
out << cacheUtils.doWithCacheWithTimeout(cacheKey, grailsApplication.config.cacheUtils.componentTimeOut as Integer){
this.renderTemplateEngineGsp(attrs)
}
}else{
out << this.renderTemplateEngineGsp(attrs)
}
}
private findSection(name){
def section
if(getCurrentComponent()){
section = Section.findByComponentInstanceAndName(getCurrentComponent(), name, [cache: true, readOnly: true])
}
if(request.currentPage && !section){
section = Section.findByPageAndName(request.currentPage, name, [cache: true, readOnly: true])
}
if(!section){
section = Section.findByName(name, [cache: true, readOnly: true])
}
section
}
private renderTemplateEngineGsp(attrs){
def componentInstance = (attrs.component ?: ComponentInstance.findByIsActiveAndName(true, attrs.name, [cache: true, readOnly: true]))
def gspText = this.replaceTemplateVariables(componentInstance.props[attrs.prop])
this.renderGsp(gspText, componentInstance, attrs)
}
private renderGsp(gspText, componentInstance, attrs){
def output = new StringWriter()
if(gspText) {
def store = storeService.getStore()
def model = [self: componentInstance, props: componentInstance.props, storeInstance: store] + attrs
groovyPagesTemplateEngine.createTemplate(gspText, componentInstance.name).make(model).writeTo(output)
}
this.debugComponent(componentInstance){
output.toString()
}
}
private replaceTemplateVariables(template){
def variablesNames = template.findAll(/\{(\w*)\}/)
if(variablesNames){
TemplateEngineVariable.createCriteria().list{
'in'('name', variablesNames)
cache true
}.each{
template = template.replace(it.name, it.value)
}
}
template
}
private renderComponentsFromSection(section , attrs) {
log.debug "Rendering Section #${section?.id} - Name: ${section?.name}"
def componentsHTML = section.activeComponents.collect { componentInstance ->
this.renderComponent(componentInstance, attrs)
}
componentsHTML.join('\n')
}
private renderComponent(componentInstance, attrs) {
this.addComponentToStack(componentInstance)
def html = this.renderTemplate(componentInstance, attrs)
if(params.editMode && Environment.currentEnvironment != Environment.PRODUCTION) {
html = this.render("/components/default/editMode/componentContainer", model:[componentInstance: componentInstance, componentView: html], componentInstance, attrs.debug)
}
this.removeComponentFromStack()
html
}
private renderTemplate(componentInstance, attrs){
def layoutDirName = storeService.getLayout().theme.directoryName
if(componentInstance && componentInstance.isActive && componentInstance.component.content){
return this.renderGsp(componentInstance.component.content, componentInstance, attrs)
}else if(componentInstance && componentInstance.isActive && componentInstance.component){
def path = "/components/${layoutDirName}/${componentInstance.component.path}"
return this.resolveTemplate(layoutDirName, path, attrs, componentInstance)
}else if(!componentInstance){
log.debug("ComponentInstance [${attrs.name}] não encontrado, renderizando componente default.")
def path = "/components/${layoutDirName}/${attrs.name}"
return this.resolveTemplate(layoutDirName, path, attrs)
}
}
private resolveTemplate(layoutDirName, path, attrs, componentInstance = null){
def debug = attrs.debug != null ? attrs.debug : true
def props = (componentInstance ? componentInstance.props : [:])
def instance = componentInstance ?: new Expando(props: [:])
if(resourceExists(path)){
render(path, [self: instance, props: props] + attrs, componentInstance, debug)
}else{
render(path.replace("/${layoutDirName}/","/default/"), [self : instance, props: props] + attrs, componentInstance, debug)
}
}
boolean resourceExists(path){
def cacheKey = createCacheKey('componentPath', path, [:])
def exists = cacheUtils.doWithCacheWithTimeout(cacheKey, grailsApplication.config.cacheUtils.gspCheckTimeOut as Integer){
def templatePath = path.split('/') as List
templatePath[templatePath.size() - 1] = "_${templatePath.last()}"
resourceService.resourceExists("${templatePath.join('/')}", grailsAttributes)
}
exists
}
private render(path, model, componentInstance, debug){
if(componentInstance && debug){
this.debugComponent(componentInstance){
g.render(template: path, model: params + model + [storeInstance: storeService.getStore()])
}
}else{
g.render(template: path, model: params + model + [storeInstance: storeService.getStore()])
}
}
private debugComponent(componentInstance, closure){
"""
<div component-id="${componentInstance?.id}" name="${componentInstance?.name}" class="component">
${closure()}
</div>
"""
}
private useCache(store){
store.enterprise && !new Boolean(request.skipCache)
}
private createCacheKey(cacheName, key, attrs){
def themeId = storeService.getLayout().theme.id
if(getCoupon()){
"${cacheName}-${key}-${attrs}-${themeId}-${params}-${getCoupon()}".hashCode().toString()
}else{
"${cacheName}-${key}-${attrs}-${themeId}-${params}".hashCode().toString()
}
}
private getCoupon() {
params.cupom ?: new String(cookieManager.getCouponCookie(storeService.store.symbol, request.cookies)?.value?.decodeBase64() ?: "")
}
private addComponentToStack(componentInstance){
if(!request.componentStack){
request.componentStack = []
}
request.componentStack << componentInstance
}
private removeComponentFromStack(){
request.componentStack.pop()
}
private getCurrentComponent(){
request.componentStack?.isEmpty() ? null : request.componentStack?.last()
}
}
def groovyPagesTemplateEngine
def index = {
request.currentPage = this.findPage()
if(request.currentPage?.content){
this.renderPage(request.currentPage)
}else{
render view: this.getViewPath(request.currentPage), model: params + [storeInstance: storeService.getStore(), props: request.currentPage?.props]
}
}
private findPage(page = params.page){
if(request.currentPage){
request.currentPage
}else if(params.pageId){
Page.findById(params.pageId as Long, [cache: true, readOnly: true])
}else{
Page.findByPath(page, [cache: true, readOnly: true])
}
}
private renderPage(page, model = [:]){
log.debug "Renderizando conteúdo customizado de página"
def output = new StringWriter()
def store = storeService.getStore()
groovyPagesTemplateEngine.createTemplate(page.content, "page_${page.id}")
.make(params + [storeInstance: store, props: page?.props] + model).writeTo(output)
render text: output.toString()
}
private getViewPath(page = null){
def view = "/stores/${storeService.getLayout().theme.directoryName}/${page?.path ?: params.page}"
(resourceExists(view) ? view : "/stores/default/${params.page}")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment