The Terrific Composer is a Frontend Development Framework – based on Symfony2 – that aims to make your life easier. It takes the modularization approach of Terrific and provides you a project structure that enables you to start right away.
The slides are part of the Terrific Composer Workshop and includes tips & tricks for working with the Composer.
9. Hold on a minute!
Before we dive deeper into the Terrific Composer…
Remo Brunschwiler # 9
10. Hold on a minute!
Before we dive deeper into the Terrific Composer…
Lets refresh our Terrific
knowledge!
http://www.slideshare.net/brunschgi/terrific-frontends
Remo Brunschwiler # 9
12. Terrific Composer
Frontend Development Framework
‣ Designed for building frontends / applications based on the
Terrific concept
‣ Integrates TerrificJS
‣ Based on Symfony
‣ … still very young
Remo Brunschwiler 10. July 2012 # 11
13. Terrific Composer
Frontend Development Framework
‣ Designed for building frontends / applications based on the
Terrific concept
‣ Integrates TerrificJS
‣ Based on Symfony
‣ … still very young
… melts dozens of best practices!
Remo Brunschwiler 10. July 2012 # 11
14. Documentation
Terrific Composer
‣ Unfortunately, a specific documentation does not exist yet
‣ Any help is gladly appreciated!!
Symfony Documentation
‣ http://symfony.com/doc/current/quick_tour/the_big_picture.html
– quick tour
‣ http://symfony.com/doc/current/book/ – really great in-depth
documentation!
‣ http://symfony.com/doc/current/cookbook/ – solutions and
tutorials for common tasks
‣ http://symfony.com/doc/current/components/index.html –
symfony components documentation
Remo Brunschwiler 10. July 2012 # 12
18. Create
Add new Modules & Skins to your project.
The Skeleton is generated for you so that
you can start right away.
Remo Brunschwiler 10. July 2012 # 16
19. Open
The Open dialog provides you fast access to
all of your Modules and Pages.
Remo Brunschwiler 10. July 2012 # 17
20. Inspect
The inspect mode shows you which modules
are in use on the current page.
Remo Brunschwiler 10. July 2012 # 18
22. Twig
Symfony comes with a powerful templating language called Twig
‣ http://symfony.com/doc/current/book/templating.html
‣ http://twig.sensiolabs.org/documentation
…I couldn’t have explained it better, so have a look at the links
above :-)
Remo Brunschwiler 10. July 2012 # 20
23. IDE Integration
Twig is a quite young project, but there is already support for
several IDEs:
‣ PhpStorm (native as of 2.1) – recommended!!
‣ Textmate via the Twig bundle
‣ Vim via the Jinja syntax plugin
‣ Netbeans via the Twig syntax plugin
‣ Eclipse via the Twig plugin
‣ Sublime Text via the Twig bundle
‣ Coda 2 via the other Twig syntax mode
Remo Brunschwiler 10. July 2012 # 21
25. Step by Step
Common Tasks
‣ Create a new page
‣ Create a new Module / Skin
‣ Create a new layout
‣ Development -> Productive
Remo Brunschwiler 10. July 2012 # 23
27. … Let’s see it in action
Remo Brunschwiler 10. July 2012 # 25
28. Create a new page
Things to do
1. Create a new or extend an existing controller
2. Create an action in the controller
3. Set annotations (@Template, @Route, @Composer)
4. Create a view (twig file) in /Resources/views/
Remo Brunschwiler 10. July 2012 # 26
29. 1. Create / Extend Controller
<?php
namespace TerrificCompositionController;
use SymfonyBundleFrameworkBundleControllerController;
use TerrificComposerBundleAnnotationComposer;
use SensioBundleFrameworkExtraBundleConfigurationRoute;
use SensioBundleFrameworkExtraBundleConfigurationTemplate;
class DefaultController extends Controller
{
}
Things to consider
‣ PHP 5.3 namespace describes where the class is located
‣ Filename = ClassName, eg. DefaultController.php
-> needed for classloading
‣ PHP 5.3 use statements for base controller and annotations
Remo Brunschwiler 10. July 2012 # 27
30. 2. Create Action
class DefaultController extends Controller
{
/**
* @Composer("Welcome")
* @Route("/", name="home")
* @Template()
*/
public function indexAction()
{
return array();
}
}
Things to consider
‣ action name must end in Action
‣ return statement of an action is a Response object
-> in our case it is and array: because of @Template()
Remo Brunschwiler 10. July 2012 # 28
31. 3. Set Annotations
/**
* @Composer("Welcome")
* @Route("/", name="home")
* @Template()
*/
public function indexAction()
{
return array();
}
@Composer(<name>)
‣ The given name will appear in the open dialog
@Route(“<path>”, name=”<name”)
‣ Describes the path under which the page is available
‣ For more options have a look at @Route
@Template()
‣ Specifies which template should be rendered (@Template documentation)
Remo Brunschwiler 10. July 2012 # 29
32. 4. Create Twig View
/Resources/views/<ControllerName>/<actionName>.html.twig
{% extends 'TerrificComposition::base.html.twig' %}
{% block title %}Terrific Composer - Welcome{% endblock %}
{% block body %}
<div class="page">
… here comes your stuff …
</div>
{% endblock %}
Things to consider
‣ Extend the layout of your choice
‣ Override / Extend the twig blocks you need
Remo Brunschwiler 10. July 2012 # 30
33. Twig Blocks
Provided from TerrificCoreBundle::base.html.twig
‣ title – content of the <title> element
‣ meta – for meta tags (<meta charset="UTF-8"/> is always set)
‣ styles – the place for your stylesheets
‣ body_class – allows you to give your body a class
‣ composition – your content goes here
‣ jquery – jquery script element
‣ terrificjs – terrificjs script element
‣ scripts – the place for your javascripts
‣ bootstrap – the default terrificjs bootstrap
Remo Brunschwiler 10. July 2012 # 31
34. Hands on!
Create a new page that…
‣ is available under /workshop
‣ appears in the open dialog as “Workshop”
‣ has the same content as the homepage
Remo Brunschwiler 10. July 2012 # 32
35. Hands on!
Create a new page that…
‣ is available under /workshop
‣ appears in the open dialog as “Workshop”
‣ has the same content as the homepage
Enhance the page, so that…
‣ you can type an URL like /workshop/{title}
‣ the {title} is displayed as heading before the Intro module
‣ and if no title is given, “Terrific Composer” should be displayed
instead
Remo Brunschwiler 10. July 2012 # 32
36. Twig Module Macro
{#
Renders terrific modules.
@param name {String} name of the module
@param view {String} name of the view to render (without html.twig suffix) [optional]
@param skins {Array} contains the skins to apply [optional]
@param connectors {Array} contains the channel ids to connect to [optional]
@param attrs {Object} contains the additional html attributes for the module [optional]
@param data {Object} contains the data to pass to embedded controllers [optional]
#}
{% macro module(name, view, skins, connectors, attrs, data) %}
To consider
‣ Twig 1.x does not support things like:
{{ tc.module('Intro', attrs={'data-name' : 'einstein'}) }}
-> this is going to change with Twig 2.0
Remo Brunschwiler 10. July 2012 # 33
37. Render Modules #1
Simple views without logic
{# this render the template with the same name (intro.html.twig) #}
{{ tc.module('Intro') }}
{# this renders the mrterrific template from the Hero Module #}
{{ tc.module('Hero', 'mrterrific')}}
{# the 3rd param is the Skins array, ie. Mr. Terrific is getting decorated
with the Stealth Skin #}
{{ tc.module('Hero', 'mrterrific', [ 'Stealth' ])}}
{# the 4th param is an array with communication channel ids, ie. all
modules with the same id can talk with each other #}
{{ tc.module('Hero', 'mrterrific', ['Stealth'], ['talk'])}}
{# the 5th param is the attrs object #}
{{ tc.module('Hero', 'mrterrific', null, null, { ‘data-name’ :
‘Mr. Terrific‘})}}
Remo Brunschwiler 10. July 2012 # 34
38. Render Modules #2
Complex views
‣ the concept is – thanks to TWIG – very simple
http://symfony.com/doc/current/book/
templating.html#embedding-controllers
‣ have their own controllers, actions & templates
‣ gives you Multi-MVC out-of-the-box
‣ are used rarely in plain “templating” projects
{{ tc.module('Filter','Filter:overspeed', null, null, null, {'segment':'washing'})}}
embeds the view of the FilterController/ the data passed to the
overspeedAction in the Filter module overspeedAction
Remo Brunschwiler 10. July 2012 # 35
39. Hands on!
Enhance your workshop page, so that…
‣ only two of the heroes can talk with each other
‣ the {title} is rendered inside the speech bubble of Einstein
Remo Brunschwiler 10. July 2012 # 36
41. What we want to achieve
Create a new «Victim» module, that…
‣ consists of a normal image (drowning man) & a background
image (bubble)
‣ uses less for better code
‣ is able to call our heroes for help
Remo Brunschwiler 10. July 2012 # 38
42. Markup
<div class="bubble">
<span class="message">help!</span>
</div>
<img src="
{{ asset("bundles/terrificmodulevictim/img/drowning-victim.png") }}
"/>
<a class="base" href="#help">Call for help!</a>
links to image asset in /web/bundles/…
But how is the drowning-victim.png got there?
‣ The composer copies all module images on the fly to
/web/bundles/<bundle>/img/ (configurable in config_dev.yml)
How did you come up with that path?
‣ Symfony standard: app/console assets:install
Remo Brunschwiler 10. July 2012 # 39
45. There is even more to less! Have a look at the documentation
‣ http://lesscss.org
Remo Brunschwiler 10. July 2012 # 42
46. TerrificJS
on:function (callback) {
var self = this,
$ctx = this.$ctx;
$('a', $ctx).on('click', function() {
var message = $('.message', $ctx).text();
self.fire('message', { name: 'drowner', message: message });
return false;
});
callback();
}
Nothing special here, but mention the new naming of the hooks in
TerrificJS v2.0
Remo Brunschwiler 10. July 2012 # 43
47. Hands on!
Create a skin for your Victim that lets him drown when there is no
help from one of the heroes
‣ Create skin “Drown” for your Victim
‣ Write a simple drown functionality (eg. fadeOut)
‣ Trigger this functionality automatically after ~5 seconds
‣ Do not let your Victim drown when he calls for help within the
given time frame
Remo Brunschwiler 10. July 2012 # 44
49. Layouts
A layouts job is to do stuff that is common to several pages
‣ javascripts
‣ styles
‣ meta tags
‣ header, footer, sidebar etc.
Thanks to TWIG & Assetic, layouts are no longer a big & inflexible
thing…
Remo Brunschwiler 10. July 2012 # 46
50. Twig Layout Approach
In Twig a layout is nothing more than an inherited template
‣ http://symfony.com/doc/current/book/templating.html#template-
inheritance-and-layouts
In your page: this is your layout
{% extends 'TerrificComposition::base.html.twig' %}
{% block title %}Terrific Composer - Welcome{% endblock %}
{% block body %}
<div class="page">
… here comes your stuff …
</div>
{% endblock %}
Remo Brunschwiler 10. July 2012 # 47
51. Twig Layout Approach
In TerrificComposition::base.html.twig
{% extends 'TerrificCoreBundle::base.html.twig' %} Terrific Core Layout
{% block title %}Terrific Composer{% endblock %}
…
{# content that is the same on every page goes into composition #}
{% block composition %}
{# your page content goes into body #}
{% block body %} this block is overridden in your page
{% endblock %}
{% endblock %}
…
Remo Brunschwiler 10. July 2012 # 48
52. Including JavaScripts
Symfony comes bundled with a very nice Assetic integration
Including JavaScripts has never been easier
concatenates – and minifies in production
{% block scripts %} mode – all files in this directory
{# here comes your scripts #}
{% javascripts
'@TerrificComposition/Resources/public/js/*.*'
output='js/compiled/statics.js' the name of the compiled file
%}
<script src="{{ asset_url }}" type="text/javascript"></script>
{% endjavascripts %}
{# scripts from parent (terrific core) layout #}
{{ parent() }} includes the content of the parent block
{% endblock %}
Remo Brunschwiler 10. July 2012 # 49
53. Including Stylesheets
… and the same for stylesheets
concatenates – and minifies in production
mode – all of the given files
{% block styles %}
{% stylesheets
'@TerrificComposition/Resources/public/css/reset.less'
'@TerrificComposition/Resources/public/css/grid.less'
'@TerrificComposition/Resources/public/css/elements.less'
output="css/compiled/project.css" the name of the compiled file
%}
<link rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}
{# styles from parent (terrific core) layout #}
{{ parent() }} includes the content of the parent block
{% endblock %}
Remo Brunschwiler 10. July 2012 # 50