Silverstripe Template Issue - templates

I'm getting to grips with the Silverstripe framework and I've come across a strange error.
Say for example I want to create a new 'membership' page. Within mysite/code I have set up a membership.php page as follows:
class Membership extends Page {
}
class Membership_Controller extends Page_Controller {
}
Then I have created a membership.ss file within my templates/layout folder with some test output. I then do a dev build and create a page in the CMS of type 'membership'. On the front end if I click the new page form the nav bar membership I don't see the test text so it seems that the template is not being read?
Any ideas?
Thanks.
Alan.

There are several common pitfalls regarding templates:
how flushing works has changed several times in the past versions.
I will not explain the details here, as those are prossibly subject to change soon again.
However there are 2 things in the current version (3.1) that is of relevance here:
/dev/build does NOT flush at all
/dev/build?flush=1 does ONLY flush manifest and config (NO templates)
(dev build does not use the template, so there is no flushing the template performed)
this means that you have do do a ?flush=1 on a normal page, not just on dev/build
The Template file has to be named exactly like the class (I think its case sensitive)
check that the template file is not overwritten by another template file in another location. (eg if you have moduleName/templates/Foo.ss and themes/simple/templates/Foo.ss than the template of the theme will overwrite the module template
make sure the template is not empty (this causes an error in SilverStripe, at least in version 3.1)
Actions on a Controller can overwrite template ussage. here some examples:
// this will not use a template at all, it will just print "some string"
public function index() { return "some string"; }
// this will not use a template at all, it will output an empty string
public function index() { return; }
// this will use template named "Bar.ss"
public function index() { return $this->renderWith(array('Bar')); }
SilverStripe also provides a debug option to see what templates are used.
you can active it by 2 ways:
set source_file_comments in your yml config:
SSViewer:
# display template filenames as comments in the html output
source_file_comments: true
use the "URL Variable Tools": just add ?showtemplate=1 when viewing your website
when enabled, see the HTML source (CTRL+u in firefox) of the page
silverstripe will add comments to let you know what templates are used.

Make sure your class has a Page_Controller extension declared and named correctly. I recently had this issue. The page controller extension had a typo, so the template file was not being used.
So for example, if your page class is RidiculouslyNamedPage
class RidiculouslyNamedPage extends Page {
}
class RidiculouslyNamedPage_Controller extends Page_Controller {
}
Then in your themes/[theme-name]/templates/Layout/ folder you would have your RidiculouslyNamedPage.ss.
If you misspell RidiculouslyNamedPage_Controller the template will not get called.

I found the answer to the problem.
My .php was missing the following:
function getInfo() {
return $this->renderWith('Media');
}
ithout this the Media.ss file will not be used! Hopefully this will help other who might be getting to grips with SS!

Related

CakePHP Exception change template

How to replace just one exception template for own exception inside a plugin, which is extended built-in exception? :)
Exception located is in /vendor/author/pluginName/src/Exception/TestException.php
But i try replace template by create file /src/Template/PluginName/Error/test.ctp but doesn't work.
Of course, if I create file inside /src/Template/Error/test.ctp works fine.
I have many plugins and each can has own TestException class.
So, How I can use /PluginName direcotry?
Cake 3.6
The correct template path for overriding a plugin template on app level starts with Template/Plugin/, followed by the plugin name and the expected local template path, ie for a plugin named Foobar, the path for overriding its test error template would be:
src/Template/Plugin/Foobar/Error/test.ctp
Also it's important to keep in mind that error templates will by default only be looked up in plugins, if the exception is being triggered in a plugin controller request, to be specific, when the current global request object (Router::getRequest(true)) has a plugin parameter set ($request->getParam('plugin'))!
It should also be noted that individual templates that map to exception/method names, will only be used for non-HTTP exceptions (\Cake\Http\Exception\HttpException), and only when debug mode is enabled, if it's a HTTP-Exception or debug mode is disabled, then only the error400 or error500 template will be used!
See also
Cookbook > Plugins > Plugin Views > Overriding Plugin Templates from Inside Your Application

Create variable accessible through all templates in PrestaShop

I understood that if I want to make my own template variable in PrestaShop, I would use code like this:
$this->context->smarty->assign( 'varName', 'varValue' );
I also understood that the right way to add this is putting it into a controller... and it all works...
What I can't figure out is how to do this in one place but still being able to access the template variable in ALL templates (my theme's .tpl files)?
PS: Adding it to all controllers seems redundant... I tried to google it out, but I guess I am putting bad keywords to search for...
So I found a solution.
What you want to do is to put your variable definition in some "general" controller - for frontend it is the FrontController. A better way then to edit the core file, is to make an override so I will show you all you need to do - considering PrestaShop 1.6 :
Create a file called FrontController.php and put it in override/classes/controller
Create a content of this file - handy method to override is initHeader(), because the variable will be available in header.tpl and all templates that are using it(tested in header.tpl and index.tpl).
Content of override/classes/controller/FrontController.php:
class FrontController extends FrontControllerCore {
public function initHeader(){
//create your variable
self::$smarty->assign('yourVariable', 'valueOfYourVariable');
//call original method, to maintain default behaviour:
return parent::initHeader();
}
}
Load the override=> go to cache directory (from shop root) and edit file called class_index.php:
find array with key "FrontController" (search for 'FrontController' or "FrontController")
in this array change "WHATEVER" in 'path' => 'WHATEVER', to override/classes/controller/FrontController.php so you will get: 'path' => 'override/classes/controller/FrontController.php',
Use your variable freely in template files as {$yourVariable}
Reference: http://doc.prestashop.com/display/PS16/Overriding+default+behaviors
you can do with modules also, prestashop provides hooks, we can use the header hook inside our module and pass the variables to smarty from the header hook function. The header hook is available on all pages
public function hookHeader($params)
{
$this->smarty->assign(array('var1' => 'value 1', 'var2' => 'value 2', 'var3' => 'value 3',));
}

silverstripe Sitetree onAfterWrite - renderWith Error: Template not found

for the automated generation of pdfs from the page content I want to use the renderWith function within onAfterWrite in the Page Class (later with DOMPDF the PDF will be generated from the returned HTML):
public function onAfterWrite() {
parent::onAfterWrite();
$this->renderPdf();
}
public function renderPdf() {
return $this->renderWith(array('Pdf'));
}
There is always this Error returned when saving the Page: None of these templates can be found in theme 'mytheme': Pdf.ss
The Template exists for sure and calling the Function renderPdf via a Template works perfectly. This is a bit weird. (ss 3.1.1)
many thanks,
florian
EDIT: maybe it is related to 3.1, I just tested in 3.0.5. without any issues. In a clean 3.1.2 install I was able to reproduce the error.
Where is your template located exactly?
Have you tried to put it under the 'templates' folder, and not under 'Layout' or 'Includes'?
In your case, I would try to move that file here:
/themes/mytheme/templates/Pdf.ss
As you are calling for a standalone template (so not alongside 'Page' for example), the .ss file should be accessible as a 'root' template, as opposed to a layout template.

Pass specific converters/templates to template with jsViews/jsRender

I am trying to pass in converters and/or templates only to a specific template. According to the API you can only pass in helpers, but not converters or templates.
Is there any way to do this or does someone know if it is planned to support this in the future?
Note Passing them in globally via $.views.templates({...}) or $.views.converters({...}) is not really an option, because I will have way to many and perhaps even name-conflicting templates and converters.
You can declare converters with your templates - and they will be private to the template. See Registering templates: $.templates(). Look for "Advanced scenarios: Associating private resources with templates".
In addition, the API for registering converters: $.views.converters({...}) also allows you to register a converter (or a set of converters) either globally, or locally just for a specific template. See the section "Adding converters as private resources for a parent template". To make them local, or private, to a template, just pass in the template as last parameter in your converters() call.
So here is a template with its own special converter declared along with the template:
$.templates({
myTemplate: {
markup: "Use my converter {{myconv:name}}",
converters: {
myconv: function(val) { return myCalculatedValue; }
}
}
});
Now {{myconv:...}} is specific to myTemplate and won't be available elsewhere.
Now suppose I want to dynamically replace the "myconv", still just within myTemplate. I can add/change it at any time using the converters() API:
$.views.converters(
"myconv",
function(val) { return myNewUpdatedCalculatedValue; },
$.templates.myTemplate // Only override it for myTemplate, not globally...
);
Here are some related links:
http://www.jsviews.com/#samples/jsr/converters
http://www.jsviews.com/#samples/form-els/converters
http://www.jsviews.com/#samples/data-link/hover (This one declares a 'private' converter)

A few questions about CodeSmith

I have recently started studying CodeSmith and I have a few questions.
I would like to make a template with 4 blocks.
Each block will be selected by the user.
How can I set the text block
(function) to selecting user?
How can I move blocks in separate
files?
For example there is a template
using System;
public class Hello3
{
public static void Main(string[] args)
{
Blocl 1
Blocl 2
Blocl 3
Blocl 4
}
}
Each of these blocks should be selected by the user. Each block is stored in a separate file.
Each block is a function. The output of one block enters to the input of another block.
P.S. Sorry for my bad english.
You could use a string property to set the name of a template or generated value. Then you would just render this string content during generation time.
Another option would be to create an enum that names different Code Blocks. Then inside of your template you could render a sub template or return some static text.
You could also create a custom dropdown list that allows you to choose a CodeSmith template. All of this logic would need to happen in a UITypeEditor and you would need to return a CodeTemplate using the API. This is a lot tougher than the first or second option.
I don't know how to do it using CodeSmith, but you would be better off using a "building-blocks" approach. AtomWeaver offers a way to build a code generator by smaller parts, called "Atoms". These Atoms are Templates that you can combine together.
In you case, I would build an Atom Template called cs_class:
The Template's Exec Code would be:
code([[
using System;
public class Hello3
{
public static void Main(string[] args)
{
{{code_blocks}}
}
}
]])
Notice the {{code_blocks}} marker. Another Template will put some code there.
Then, create the cs_code_block Atom Template. Use this code:
For the Admin Section:
under("cs_class")
For the Exec Section:
cursor("code_blocks")
code([[
<put user code here>
]])
The under() command helps you build an interactive modeling environment in AtomWeaver. Now, your user can create a model with one cs_class Atom, and then he can add as many cs_code_block Atoms as he wish. Executing the model will generate the desired code.
AtomWeaver lets you evolve your models and code generators. It's easy to start with a few lines and then grow it to obtain complete generators.
I know this is a very, very simplistic example of what you can build with AtomWeaver, but it's just to give you a quick idea of what you can accomplish.