I am about to build a modular page theme in grav (which uses twig as a template engine).
By default, a modular theme consists of at least two twig template files: one provides the page frame including the head and another one that provides the markup of a content module. Grav's standard theme provides examples of these templates:
modular page frame example
module example
As you can see, the module (example) does not have a head or javascripts block to add javascripts to the html head. (This wouldn't even be possible, as a typical modular page consists of multiple modules. So if two different modules would try to change the javascripts block the last one would overwrite the changes made by the first one which would lead to unintended results).
However, it happens that I need to add some javascript code to the head of my page from within a module. I thought about a solution and had the idea to add the javascript-code as a property to an object that exists "site wide", namely the pages object.
This leads to my question:
How can I add properties to an existing object using the twig syntax?
Apart from that I would also like to know if you can think of any reasons why this solution could possibly not work. But if you help me with the syntax, I can also just give it a try...
Manipulating the state of an object shouldn't be done in a Twig template. The view should be outputting data that has been supplied to it.
try to change the javascripts block the last one would overwrite the changes made by the first one which would lead to unintended results
See this answer here for an explanation of how to have multiple blocks append content to a block rather than overwrite it. You can simply have a 'extra_scripts' block or something like that, then append any required javascript for a particular module to that block as per the described link. Essentially you need to use {{ parent() }} to ensure content is included from the parent
Related
I am building a page with PHP and am making heavy use of templating to split the various parts of each page up into reusable components, each of which has its own stylesheet which is automatically added to the head by script.
However, to save bandwidth and avoid style conflicts in certain situations, I would like to only link those stylesheets which are actually used on a given page. Since the head goes first in the page and the styles go in the head, but there's no way to access something like get_included_files() until the end of the page, I'd (presumably) need a way to reach back into the head and add the link tags later, but I'm not sure how to do that.
The only obvious way I can think of is to necessitate a registry array of all the components which will be used, and then use that to generate the link tags, but that is not really viable because some of the components include other components, so it would be necessary to manually register not just the components included in the top-level file, but all the components included by those components as well.
I figured out a solution. I took each of my components, and basically wrapped them in a class and a public static function of that class, called output(). I can now include() all the components I want to use right at the start, and then just do Component::output() wherever I want it to appear. This way, all the files are included, and visible to get_included_files(), by the time I call output() on the script that generates the head.
I'm using view blocks to allow individual views to add scripts and stylesheets that are specific to those views. The resources that are used everywhere are included by default in the layout. Here's the documentation on view blocks.
Everything works as described, but the content appended in my views was getting added BEFORE the default block content (even though I was using $this->append('block name')). After a lot of aggravation, I deduced that the views were actually getting referenced first, before the layout. So the scripts I was loading in the view were getting appended to nothing. Then the layout's scripts were getting appended afterwards.
I was able to solve this problem my removing my global scripts OUTSIDE of the block. But I don't like this approach for a couple reasons. In the future, I may want my view to be able to overwrite certain things. Also, it just seems wrong and counter to what view blocks are meant for.
My questions:
1. Is the behavior I described the intended behavior?
2. Is there a better work-around to manage script dependancies from scripts appended from views?
I think blocks should not be defined in layouts, that's not the way it is intended for, it should be defined in views or elements, appended by other views or elements, and then fetched by layouts or views.
I'm trying to set up a Joomla-template in a way which allows me to use template parameters to choose between a number of layout variations of the template from the admin-interface. The idea is that the index.php only contains a statement which includes a php-file from a folder within the main template folder, based on the template parameters passed.
Unfortunately it seems thatmy jdoc module positions breaks whenever they are located outside the index.php file, even though it is referenced by an include-tag.
The problem is in the order that the framework builds index.php. Rather than trying to use include files, you can accomplish the same goal in a much easier and cleaner fashion. Using a combination of collapsible module positions and CSS you can manipulate the template to do basically anything you want.
You can also use template styles if you are using J1.7. A template style is basically a variation of a template that is assigned to specific menu items. Either way will work.
For a while now I've been wrestling with the issue of dynamic forms that change depending on previous input. This is my first Symfony project, so I'm still getting the hang of how everything works together.
What I have is a form type for selecting periods of time. There are preset periods (such as 1min, 5min, 30min, 1hour etc) and a custom text box for entering a certain number of seconds. This form can be embedded in other forms, so (afaik) doesn't have a standard ID that can be accessed. I would like the custom time text box to be only visible if the "Custom Time" (empty value) is selected from the preset time list.
Alternately, the preset values could just write a value in seconds to the custom value (and would need to have the preset box changed to custom on modification of the custom text box). That would be acceptable too.
If the form builder wasn't being used, this would be trivial JavaScript but rather than hacking something together, I would much rather do it properly in reusable code so that I know for the future. To my way of thinking, if there was a way of specifying a custom form rendering template in the form type itself that applied only to that form, that would be fantastic.
Fingers crossed that there's a good solution to this!
Edited: Also, I'm using Twig for rendering all my views.
Results of a bit of research concluded that the best way to do this is to add field overrides for the widget:
/src/PWT/DataBundle/Resources/views/Form/fields.html.twig:
{% block periodChoose_widget %}
<script type="text/javascript" src="{{ asset('bundles/databundle/js/periodChoose.js') }}"></script>
{{ block('form_widget') }}
{% block %}
Then add the following to each of the app/bundle config files:
/app/config/config.yml:
imports:
data_bundle:
resource: #PWTDataBundle/Resources/config/config.yml
/src/PWT/DataBundle/Resources/config/config.yml:
# Twig Configuration
twig:
form:
resources:
- 'PWTDataBundle:Form:fields.html.twig'
I realized that I would need to add something in the global app config if I wanted to reuse the form across multiple bundles. This allows the bundle to be reasonably self contained, with only a small reference in the overall app config. The javascript is not included until the form is used, and the twig block has very little overhead compared to other solutions (afaik).
This way, the javascript that goes with the form is included whenever it is used, and to modify it only requires modification of the bundle, not anything in the overall app config/views. It also breaks the views up so that they don't have a long list of extends this, extends that (like would need to be applied if you had a bundle style that added formTheme tag to override on the base bundle template).
Some of those last 2 paragraphs is speculation, and there could easily be a far better way to do this but this is an adequate fit for me to move on. If anyone has a better solution, I would be happy to read about it.
How does Drupal 7 render out a page? What's its equivalent to an MVC's view system.
When it comes to the rendering out the final HTML page for a request, most PHP frameworks (MVC based) I've worked with take an approach where a top-level layout/page PHP file sets out the basic document structure, and then renders our various sub-views via includes or view rendering methods.
//Simplified version
Page.phtml
Head.phtml
Body.phtml
Banner.phtml
Topnav.phtml
Left.phtml
Content.phtml
Footer.phtml
I'm a little confused as to Drupal's take on this. I'm reading through Pro Drupal Development, and it starts off in similar territory with a page.tpl.php. However, it glosses over how the theme engine (is that the right term?) gets the various parts of PHP into this page (not a criticism, the book's taking an approach that different from the path I'm on).
Also, the Drupal 7 themes don't seem to have the page.tpl.php file, so its not clear (to me) where the page skeleton comes from. Also, from what I've read it seems like "Blocks" are involved, but it's not clear to me if "Blocks" makeup the entire page, or if blocks are something used selectively by themes.
So, working from high level concepts (or get as detailed as you'd like), how does Drupal 7 render out a page?
I realize you can, and probably should, start with Drupal without understand how everything ties together. I'm specifically trying to learn how the various Drupal systems come together. Apologies to people tired of reading this disclaimer!
I think there are two questions here. First, how does a single theme/template get rendered/used/displayed and second, how does the whole site come together. I think the second question has already been answered above, so I'm going to try to explain the first a bit more.
First, a module (that's why system.module exists, for all these stuff that only a module can do like implementing hook_menu()) needs to define that a specific theme function/template exists, by declaring it in hook_theme()
Speaking of that, there are two different things which can be used. A theme function, which is a function prefixed with theme_. Often used for smaller elements of a page wich have more complex logic/PHP like theme_table(). And a template, which is a file with the tpl.php like page.tpl.php
To use a theme function/template, you can either call theme() like this:
$output = theme('table', array('rows' => $rows, 'header' => $header));
Or you can use the new, so called renderable array thing. That is basically an array of data + information which theme to use:
$output = array(
'#theme' => 'table',
'#rows' => $rows,
'#header' => $header,
);
The second is preferred because it means that it will be themed as late as possible and other modules can change it in hooks. The result will be exactly the same, drupal_render() will then call theme() itself during the final rendering.
When theme() is called, it looks up the function/file to use, looks if it has been overriden the used theme, if there are so called template suggestions and then uses them.
To override a theme function in a theme, copy it to your template.php file and replace "theme_" with "yourthemename_", if it is a tpl.php file, copy it to your directory.
Now, what the final rendering process is doing is basically building up a large $page array, that is a renderable array (Some documentation of that is in hook_page_alter() and then call drupal_render() on it.
The global structure of the page/template hierarchy (which is not hardcoded, but given through whatever is in $page) is something like this:
html.php.tpl
head.php.tpl
page.php.tpl
multiple regions
multiple blocks
Almost everything is a block in Drupal 7, including the actual content, which is typically a node. A theme defines which regions it has and then you can assign blocks to it in the UI.
When trying to understand how the templates fit together, the best tool I've found is the Theme Developer module. It works a little like Firebug and allows you click on areas of a page to see the theme functions or template files that are used for various parts of the page, along with the "suggestions" that can be used for overriding them.
Templates can fit together in a variety of ways. Drupal does make some assumptions about how they'll be nested, which are reflected in the default variables that are available in the templates files. However, both the template suggestions and the available variables within them can be modified.
As I understand it, page.tpl.php has been replaced by html.tpl.php in Drupal 7.
The best description I've heard for "Blocks" is that they're what you use to display content that will be re-used in various areas site. The most common use is for sidebars, such as "Recently updated pages" lists or "Who is online now" lists.
Try take a look a presentation on How pages are built on Drupal 7 from drupalcon at http://sf2010.drupal.org/conference/sessions/page-render-drill-down-drupal-7 specially after 5 minutes from start (05:10). Sorry can't specify much detail here cause i still watch it my self. And try to understand it as well. ;)
[Update]
After watch the presentation here is my quick conclusion on how drupal 7 render out a page:
Instead of common approach that you mention from your question
where a top-level layout/page PHP file
sets out the basic document structure,
and then renders our various sub-views
via includes or view rendering methods
Drupal render a page through a rendering flow approach like this
bootstrap
menu_execute_active_handler
page_callback
delivery_callback
hook_page_alter()
drupal_render($page)
However, it glosses over how the theme
engine (is that the right term?) gets
the various parts of PHP into this
page (not a criticism, the book's
taking an approach that different from
the path I'm on).
that various parts is served starting from rendering flow number 3 (page_callback) through flow number 6 (drupal_render($page)) where its start to return an array of drupal render-able array and then latter in your theme you can use the $page variable (served from drupal_render($page)) to render i.e drupal content.