The Symfony form documentation is better than it used to be, but forms are still one of the most tricky things to figure out.
I just wanted to save someone’s time by showing a full working example that deals with forms, doctrine, views, routing and controller issues.
I really encourage you to read Symfony official documentation about forms and Doctrine before going on with my example. It will be useful to open The Symfony2 API in a new tab.
The goal
We’ll be building this “task reminder” web app using Symfony (forms and Doctrine). Hope this helps someone.
The Model (aka Entity)
So, lets take a look at my entity\Task.php
file. Nothing fancy here. A task consists of an id
, a task
(name), a due date
, an url
and a description
. The necessary information is provided to make Symfony “understand” our Task objets and map the attributes to Database table.
Note the strategy=AUTO
parameter in Id
field. When using this, Doctrine will generate Id’s begining with 1. This is useful, as will be seen after.
To avoid writing all the (stupid) lines related to getters
and setters
you could just write the attributes, then run…
php app/console doctrine:generate:entities curso/TaskBundle/Entity/Task |
php app/console doctrine:generate:entities curso/TaskBundle/Entity/Task
… and all the necessary setters
and getters
would be created (don’t you love Symfony already?)
<?php
// src/curso/TaskBundle/Entity/Task.php
namespace curso\TaskBundle\Entity;
// para el mapping entre campos de la BD y Entity
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="task")
*/
class Task2
{
/**
* @ORM\Id
* @ORM\Column(type="integer", unique=true)
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* El nombre de la tarea, como máximo de 20 caracteres
* @ORM\Column(type="string", length=20)
*/
protected $task;
/**
* La fecha de finalización de la tarea
* @ORM\Column(type="date")
*/
protected $dueDate;
/**
* La descripción de la tarea
* @ORM\Column(type="text", length=300)
*/
protected $description;
/**
* La URL relacionada de algún modo con la tarea
* @ORM\Column(type="text", nullable=true)
*/
protected $url;
public function getTask(){
return $this->task;
}
public function setTask($task){
$this->task = $task;
}
public function getDueDate(){
return $this->dueDate;
}
public function setDueDate(\DateTime $dueDate = null){
$this->dueDate = $dueDate;
}
public function getDescription(){
return $this->description;
}
public function setDescription($description){
$this->description = $description;
}
public function getUrl(){
return $this->url;
}
public function setUrl($url){
$this->url = $url;
}
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
} |
<?php
// src/curso/TaskBundle/Entity/Task.php
namespace curso\TaskBundle\Entity;
// para el mapping entre campos de la BD y Entity
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="task")
*/
class Task2
{
/**
* @ORM\Id
* @ORM\Column(type="integer", unique=true)
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* El nombre de la tarea, como máximo de 20 caracteres
* @ORM\Column(type="string", length=20)
*/
protected $task;
/**
* La fecha de finalización de la tarea
* @ORM\Column(type="date")
*/
protected $dueDate;
/**
* La descripción de la tarea
* @ORM\Column(type="text", length=300)
*/
protected $description;
/**
* La URL relacionada de algún modo con la tarea
* @ORM\Column(type="text", nullable=true)
*/
protected $url;
public function getTask(){
return $this->task;
}
public function setTask($task){
$this->task = $task;
}
public function getDueDate(){
return $this->dueDate;
}
public function setDueDate(\DateTime $dueDate = null){
$this->dueDate = $dueDate;
}
public function getDescription(){
return $this->description;
}
public function setDescription($description){
$this->description = $description;
}
public function getUrl(){
return $this->url;
}
public function setUrl($url){
$this->url = $url;
}
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
}
Lets add some validations to that class. This is Resources/config/validation.yml
and contains the field descriptions (that will match the ones in the form definition). Along with the fields are the messages to display in case of form errors and some (stupid) URL check using a regex.
curso\TaskBundle\Entity\Task2:
properties:
task:
- NotBlank: {message: "Debes darle nombre a la tarea"}
- MaxLength: {limit: 20, message: "El nombre de la tarea no puede tener más de {{ limit }} caracteres" }
- MinLength: {limit: 1, message: "El nombre de la tarea no puede tener menos de {{ limit }} caracteres" }
dueDate:
- NotBlank: ~
- Type: \DateTime
- Date: {message: "Debes insertar una fecha válida"}
description:
- MaxLength: { limit: 300, message: "Descripción limitada a {{ limit }} caracteres" }
url:
- Url:
- Regex:
pattern: "/.*\.es$/"
message: "La URL debe terminar en .es" |
curso\TaskBundle\Entity\Task2:
properties:
task:
- NotBlank: {message: "Debes darle nombre a la tarea"}
- MaxLength: {limit: 20, message: "El nombre de la tarea no puede tener más de {{ limit }} caracteres" }
- MinLength: {limit: 1, message: "El nombre de la tarea no puede tener menos de {{ limit }} caracteres" }
dueDate:
- NotBlank: ~
- Type: \DateTime
- Date: {message: "Debes insertar una fecha válida"}
description:
- MaxLength: { limit: 300, message: "Descripción limitada a {{ limit }} caracteres" }
url:
- Url:
- Regex:
pattern: "/.*\.es$/"
message: "La URL debe terminar en .es"
At this point you should create the table in the database. I am assuming you have a MySQL server and Doctrine already configured to use it.
Well, I got good news for you. No (boring) process of table creation. Symfony does the job for you! 🙂
php app/console doctrine:schema:update --force |
php app/console doctrine:schema:update --force
The routing
Next, we should define the paths in Resources/config/routing.yml
Four paths will be defined: one for the new task, one for showing all tasks, another one to edit a task and another one to show messages (success)
Note the (security) requirement in the id parameter (must be a number!) and default id value (0 is not an index that Doctrine produces)
# src/curso/TaskBundle/Resources/config/routing.yml
cursoTaskBundle_task_new:
pattern: /new
defaults: { _controller: cursoTaskBundle:Default:new }
cursoTaskBundle_task_show:
pattern: /show
defaults: { _controller: cursoTaskBundle:Default:show }
cursoTaskBundle_task_edit:
pattern: /{id}/edit
defaults: { _controller: cursoTaskBundle:Default:edit, id: 0 }
requirements:
id: \d+
cursoTaskBundle_task_success:
pattern: /success/{nombreTarea}
defaults: { _controller: cursoTaskBundle:Default:success, nombreTarea: - } |
# src/curso/TaskBundle/Resources/config/routing.yml
cursoTaskBundle_task_new:
pattern: /new
defaults: { _controller: cursoTaskBundle:Default:new }
cursoTaskBundle_task_show:
pattern: /show
defaults: { _controller: cursoTaskBundle:Default:show }
cursoTaskBundle_task_edit:
pattern: /{id}/edit
defaults: { _controller: cursoTaskBundle:Default:edit, id: 0 }
requirements:
id: \d+
cursoTaskBundle_task_success:
pattern: /success/{nombreTarea}
defaults: { _controller: cursoTaskBundle:Default:success, nombreTarea: - }
The controller
Now, the juice. The code is explained in the comments, but is easy to follow although your spanish skills are not that great 😉
Every action that was previously defined in the routing part is created.
I would also like to share this image because it helps people understand what is going on with Forms.

<?php
// src/curso/TaskBundle/Controller/DefaultController.php
namespace curso\TaskBundle\Controller;
use curso\TaskBundle\Entity\Task;
use curso\TaskBundle\Entity\Task2;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class DefaultController extends Controller
{
/*
* Nueva tarea
*/
public function newAction(Request $request)
{
// quiero saber el anyo actual:
$thisyear = date('Y');
// vamos a crear una tarea nueva!
$task = new Task2();
$form = $this->createFormBuilder($task)
->add('task', 'text',array('label' => 'Tarea:'))
->add('dueDate', 'date', array('label' => 'Fecha limite', 'years' => range($thisyear, $thisyear+5)))
->add('description', 'textarea', array('label' => 'Descripcion', 'required' => 'false'))
->add('url', 'url', array('required' => false))
->getForm();
if ($request->getMethod() == 'POST') {
// segunda vez que se llama a newAction, ahora ya tenemos los datos
// de la tarea en el $request. Asi que hacemos el "bind" al formulario...
$form->bindRequest($request);
// y comprobamos si es válido (validation.yml!)
if ($form->isValid()){
// hacer cosas con los datos del form.
// Guardarlos en BD, p ej.
$em = $this->getDoctrine()->getEntityManager();
$em->persist($task); // = decirle a Symfony que "controle" este objeto!
$em->flush(); // podría agrupar varias queries y despues flush las lanzaría a la BD a la vez!
return $this->redirect($this->generateUrl('cursoTaskBundle_task_success', array('nombreTarea' => $task->getTask()) ));
}
}
return $this->render('cursoTaskBundle:Default:new2desplegado.html.twig', array(
'form' => $form->createView(),
));
}
/*
* Obtiene todas las tareas
*/
public function showAction(){
$tasks = $this->getDoctrine()
->getRepository('cursoTaskBundle:Task2')
->findAll();
//->findByTask('Ejemplo tarea'); //con esta línea podría buscar una tarea con ese nombre exacto
return $this->render('cursoTaskBundle:Default:show.html.twig', array(
'tasks' => $tasks
));
}
/*
* Editar una tarea
*/
public function editAction($id, Request $request)
{
if (!$id) {
throw $this->createNotFoundException('No se encuentra la tarea con id = '.$id);
}
// valido que existe la tarea asociada a ese ID...
$em = $this->getDoctrine()->getEntityManager();
$task = $em->getRepository('cursoTaskBundle:Task2')->find($id);
if (!$task){
throw $this->createNotFoundException('No se encuentra la tarea con id = '.$id);
}
// quiero saber el anyo actual:
$thisyear = date('Y');
// Creo el formulario (con sus campos) de forma dinámica.
// Como voy a repetir el formulario que ya creé en newAction, quizá sería interesante
// plantearme crear una clase aparte y usar $this->createForm para crearlo "de forma estática"
$form = $this->createFormBuilder($task)
->add('task', 'text',array('label' => 'Tarea:'))
->add('dueDate', 'date', array('label' => 'Fecha limite', 'years' => range($thisyear, $thisyear+5)))
->add('description', 'textarea', array('label' => 'Descripcion', 'required' => 'false'))
->add('url', 'url', array('required' => false))
->getForm();
if ($request->getMethod() == 'POST') {
// ya he recibido el resultado del formulario...
// mappeo los valores del request a los del form...
$form->bindRequest($request);
// y compruebo si es válido...
if ($form->isValid()){
// es válido, asi que actualizo la BD...
$em->flush();
return $this->redirect($this->generateUrl('cursoTaskBundle_task_success', array('nombreTarea' => $task->getTask()) ));
}
}
// PRIMERA INVOCACION A EDIT: hay que dejarle al user modificar la info!
return $this->render('cursoTaskBundle:Default:edit2desplegado.html.twig', array(
'form' => $form->createView(),
'id' => $task->getId(),
));
}
/*
* Mostrar pantalla de "éxito al realizar las operaciones".
*/
public function successAction($nombreTarea){
if (!strcmp($nombreTarea,"-")){
$message = "Qué tramas, moreno? ¡No deberías invocar esta URL de forma manual!";
}
else{
// Voy a generar un mensaje...
$message = "La tarea '".$nombreTarea."' se ha guardado.";
}
return $this->render('cursoTaskBundle:Default:success.html.twig', array(
'message' => $message
));
} |
<?php
// src/curso/TaskBundle/Controller/DefaultController.php
namespace curso\TaskBundle\Controller;
use curso\TaskBundle\Entity\Task;
use curso\TaskBundle\Entity\Task2;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class DefaultController extends Controller
{
/*
* Nueva tarea
*/
public function newAction(Request $request)
{
// quiero saber el anyo actual:
$thisyear = date('Y');
// vamos a crear una tarea nueva!
$task = new Task2();
$form = $this->createFormBuilder($task)
->add('task', 'text',array('label' => 'Tarea:'))
->add('dueDate', 'date', array('label' => 'Fecha limite', 'years' => range($thisyear, $thisyear+5)))
->add('description', 'textarea', array('label' => 'Descripcion', 'required' => 'false'))
->add('url', 'url', array('required' => false))
->getForm();
if ($request->getMethod() == 'POST') {
// segunda vez que se llama a newAction, ahora ya tenemos los datos
// de la tarea en el $request. Asi que hacemos el "bind" al formulario...
$form->bindRequest($request);
// y comprobamos si es válido (validation.yml!)
if ($form->isValid()){
// hacer cosas con los datos del form.
// Guardarlos en BD, p ej.
$em = $this->getDoctrine()->getEntityManager();
$em->persist($task); // = decirle a Symfony que "controle" este objeto!
$em->flush(); // podría agrupar varias queries y despues flush las lanzaría a la BD a la vez!
return $this->redirect($this->generateUrl('cursoTaskBundle_task_success', array('nombreTarea' => $task->getTask()) ));
}
}
return $this->render('cursoTaskBundle:Default:new2desplegado.html.twig', array(
'form' => $form->createView(),
));
}
/*
* Obtiene todas las tareas
*/
public function showAction(){
$tasks = $this->getDoctrine()
->getRepository('cursoTaskBundle:Task2')
->findAll();
//->findByTask('Ejemplo tarea'); //con esta línea podría buscar una tarea con ese nombre exacto
return $this->render('cursoTaskBundle:Default:show.html.twig', array(
'tasks' => $tasks
));
}
/*
* Editar una tarea
*/
public function editAction($id, Request $request)
{
if (!$id) {
throw $this->createNotFoundException('No se encuentra la tarea con id = '.$id);
}
// valido que existe la tarea asociada a ese ID...
$em = $this->getDoctrine()->getEntityManager();
$task = $em->getRepository('cursoTaskBundle:Task2')->find($id);
if (!$task){
throw $this->createNotFoundException('No se encuentra la tarea con id = '.$id);
}
// quiero saber el anyo actual:
$thisyear = date('Y');
// Creo el formulario (con sus campos) de forma dinámica.
// Como voy a repetir el formulario que ya creé en newAction, quizá sería interesante
// plantearme crear una clase aparte y usar $this->createForm para crearlo "de forma estática"
$form = $this->createFormBuilder($task)
->add('task', 'text',array('label' => 'Tarea:'))
->add('dueDate', 'date', array('label' => 'Fecha limite', 'years' => range($thisyear, $thisyear+5)))
->add('description', 'textarea', array('label' => 'Descripcion', 'required' => 'false'))
->add('url', 'url', array('required' => false))
->getForm();
if ($request->getMethod() == 'POST') {
// ya he recibido el resultado del formulario...
// mappeo los valores del request a los del form...
$form->bindRequest($request);
// y compruebo si es válido...
if ($form->isValid()){
// es válido, asi que actualizo la BD...
$em->flush();
return $this->redirect($this->generateUrl('cursoTaskBundle_task_success', array('nombreTarea' => $task->getTask()) ));
}
}
// PRIMERA INVOCACION A EDIT: hay que dejarle al user modificar la info!
return $this->render('cursoTaskBundle:Default:edit2desplegado.html.twig', array(
'form' => $form->createView(),
'id' => $task->getId(),
));
}
/*
* Mostrar pantalla de "éxito al realizar las operaciones".
*/
public function successAction($nombreTarea){
if (!strcmp($nombreTarea,"-")){
$message = "Qué tramas, moreno? ¡No deberías invocar esta URL de forma manual!";
}
else{
// Voy a generar un mensaje...
$message = "La tarea '".$nombreTarea."' se ha guardado.";
}
return $this->render('cursoTaskBundle:Default:success.html.twig', array(
'message' => $message
));
}
The Templates (view) + Assets (Css)
And last but not least, the TWIG templates I used along with the CSS.
Some days ago I wrote about how to manage Assets with Assetic. Note how this is applied here (and YUI CSS Compressor filter is used).
The first template is a general-purpose three-column layout that will be the “base” for our minisite. Let’s call it template-base-curso.html.twig
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
{% block head %}
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>
{% block title %}
{{ title|default("Template Base para TWIG") }}
{% endblock title %}
</title>
{% block description %}
<meta name="description" content="{{ description|default('Plantilla TWIG base por Miguel Martin') }}"/>
{% endblock description %}
{% block keywords %}
<meta name="keywords" content="twig, template, free, design, 960, grid" />
{% endblock keywords %}
{% block styles %}
{% stylesheets
'@cursoe5Bundle/Resources/public/css/layout/mainStyle.css'
'@cursoe5Bundle/Resources/public/css/layout/reset.css'
'@cursoe5Bundle/Resources/public/css/layout/colors.css'
output = 'css/compiled/styles.css'
filter = 'yui_css'
%}
<link href="{{ asset_url }}" type="text/css" rel="stylesheet" media="screen" />
{% endstylesheets %}
{% endblock styles %}
{% block script %}
{% javascripts
'@cursoe5Bundle/Resources/public/js/*'
%}
<script src="{{ asset_url }}" type="text/javascript"></script>
{% endjavascripts %}
<script type="text/javascript">
//<![CDATA[
//$(document).ready(function(){
//});
//]]>
</script>
{% endblock script %}
</head>
{% endblock head %}
<body>
<div id="wrapper">
<!-- ******************************************** HEADER ************************************ -->
{% block header %}
<div id="header">
<div id="titulo-centro">
<h1> {{ titulo|default("TEMPLATE BASE") }}</h1>
</div>
</div>
{% endblock header %}
<!-- ******************************************** /HEADER ************************************ -->
<div id="content">
<div id="breadcrumbs">
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="{{ path('cursoe5Bundle_homepage') }}">HOME </a></li>
<li class="actual"><a href="="{{ path('cursoTaskBundle_test_template') }}">Template</a></li>
</ul>
{% endblock breadcrumbs %}
</div>
<br />
<!-- ******************************************** LEFT-COLUMN ************************************ -->
<div id="left-column">
{% block menusub %}
<div id="menu-sub">
<ul>
<li class"=first"><a href="{{ path('cursoe5Bundle_homepage') }}">HOME </a></li>
<li class="actual"><a href="{{ path('cursoTaskBundle_test_template') }}">Template</a></li>
<li><a href="{{ path('cursoTaskBundle_task_new2') }}">Insertar tarea</a></li>
<li><a href="{{ path('cursoTaskBundle_task_show') }}">Mostrar tareas</a></li>
<li class="last"><a href="#">link 4</a></li>
</ul>
</div>
{% endblock menusub %}
</div>
<!-- ******************************************** /LEFT-COLUMN ************************************ -->
<!--====MAIN COLUMN START====-->
<div id="main-column">
{% block maincolumn %}
<h2>Template base en TWIG</h2><br />
<p class="text-justify">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum</p>
<br />
<p class="text-justify">Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</p>
{% endblock maincolumn %}
</div>
<!--====MAIN COLUMN END====-->
<!--====RIGHT COLUMN START====-->
<div id="right-column">
{% block rightcolumn %}
<p class="text-justify xxsmall">But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it?</p>
{% endblock rightcolumn %}
</div>
<!--====RIGHT COLUMN END====-->
</div>
<!--=================CONTENT END==============-->
<!--=================FOOTER START==============-->
<div id="footer">
{% block footer %}
©2012 All Rights Reserved Miguel Martin | <a href="http://www.leccionespracticas.com" target="_blank" >Design by MiguelMartin</a> | <a href="http://validator.w3.org/check?uri=referer" target="_blank" rel="nofollow" >XHTML</a> | <a href="http://jigsaw.w3.org/css-validator/" target="_blank" rel="nofollow" >CSS</a></div>
{% endblock footer %}
<!--=================FOOTER END==============-->
</div>
</body>
</html> |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
{% block head %}
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>
{% block title %}
{{ title|default("Template Base para TWIG") }}
{% endblock title %}
</title>
{% block description %}
<meta name="description" content="{{ description|default('Plantilla TWIG base por Miguel Martin') }}"/>
{% endblock description %}
{% block keywords %}
<meta name="keywords" content="twig, template, free, design, 960, grid" />
{% endblock keywords %}
{% block styles %}
{% stylesheets
'@cursoe5Bundle/Resources/public/css/layout/mainStyle.css'
'@cursoe5Bundle/Resources/public/css/layout/reset.css'
'@cursoe5Bundle/Resources/public/css/layout/colors.css'
output = 'css/compiled/styles.css'
filter = 'yui_css'
%}
<link href="{{ asset_url }}" type="text/css" rel="stylesheet" media="screen" />
{% endstylesheets %}
{% endblock styles %}
{% block script %}
{% javascripts
'@cursoe5Bundle/Resources/public/js/*'
%}
<script src="{{ asset_url }}" type="text/javascript"></script>
{% endjavascripts %}
<script type="text/javascript">
//<![CDATA[
//$(document).ready(function(){
//});
//]]>
</script>
{% endblock script %}
</head>
{% endblock head %}
<body>
<div id="wrapper">
<!-- ******************************************** HEADER ************************************ -->
{% block header %}
<div id="header">
<div id="titulo-centro">
<h1> {{ titulo|default("TEMPLATE BASE") }}</h1>
</div>
</div>
{% endblock header %}
<!-- ******************************************** /HEADER ************************************ -->
<div id="content">
<div id="breadcrumbs">
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="{{ path('cursoe5Bundle_homepage') }}">HOME </a></li>
<li class="actual"><a href="="{{ path('cursoTaskBundle_test_template') }}">Template</a></li>
</ul>
{% endblock breadcrumbs %}
</div>
<br />
<!-- ******************************************** LEFT-COLUMN ************************************ -->
<div id="left-column">
{% block menusub %}
<div id="menu-sub">
<ul>
<li class"=first"><a href="{{ path('cursoe5Bundle_homepage') }}">HOME </a></li>
<li class="actual"><a href="{{ path('cursoTaskBundle_test_template') }}">Template</a></li>
<li><a href="{{ path('cursoTaskBundle_task_new2') }}">Insertar tarea</a></li>
<li><a href="{{ path('cursoTaskBundle_task_show') }}">Mostrar tareas</a></li>
<li class="last"><a href="#">link 4</a></li>
</ul>
</div>
{% endblock menusub %}
</div>
<!-- ******************************************** /LEFT-COLUMN ************************************ -->
<!--====MAIN COLUMN START====-->
<div id="main-column">
{% block maincolumn %}
<h2>Template base en TWIG</h2><br />
<p class="text-justify">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum</p>
<br />
<p class="text-justify">Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</p>
{% endblock maincolumn %}
</div>
<!--====MAIN COLUMN END====-->
<!--====RIGHT COLUMN START====-->
<div id="right-column">
{% block rightcolumn %}
<p class="text-justify xxsmall">But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it?</p>
{% endblock rightcolumn %}
</div>
<!--====RIGHT COLUMN END====-->
</div>
<!--=================CONTENT END==============-->
<!--=================FOOTER START==============-->
<div id="footer">
{% block footer %}
©2012 All Rights Reserved Miguel Martin | <a href="http://www.leccionespracticas.com" target="_blank" >Design by MiguelMartin</a> | <a href="http://validator.w3.org/check?uri=referer" target="_blank" rel="nofollow" >XHTML</a> | <a href="http://jigsaw.w3.org/css-validator/" target="_blank" rel="nofollow" >CSS</a></div>
{% endblock footer %}
<!--=================FOOTER END==============-->
</div>
</body>
</html>
The view associated with “INSERT NEW TASK” is new2desplegado.html.twig
. Please note how the form is displayed here!
{# src/curso/TaskBundle/Resources/views/Default/new2desplegado.html.twig #}
{% extends "cursoTaskBundle:Default:template-base-curso.html.twig" %}
{% block title %}
Insertar nueva tarea
{% endblock title %}
{% block header %}
<div id="header">
<div id="titulo-centro">
<h1>INSERTAR NUEVA TAREA</h1>
</div>
</div>
{% endblock header %}
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="/">HOME </a></li>
<li class="actual"><a href="/curso/template">Template</a></li>
<li class="last"><a href="/curso/new2">Nueva tarea</a></li>
</ul>
{% endblock breadcrumbs %}
{% block maincolumn %}
{% block message %}
{% endblock message %}
<div id="form-div" style="width: 800px; margin:auto; padding:10px;">
<form action="{{ path('cursoTaskBundle_task_new2') }}" method="post" {{ form_enctype(form) }}>
<div id="errores_form" class="error">
<!-- errores generales del formulario -->
{{ form_errors(form) }}
</div>
<div id="formcontent">
<table style="border-collapse:separate; border-spacing:1em;">
<tr>
<td>{{ form_label(form.task) }}</td>
<td>{{ form_widget(form.task) }}</td>
<td class="error">{{ form_errors(form.task) }}</td>
</tr>
<tr>
<td>{{ form_label(form.dueDate) }}</td>
<td>{{ form_widget(form.dueDate) }}</td>
<td class="error">{{ form_errors(form.dueDate) }}</td>
</tr>
<tr>
<td>{{ form_label(form.description) }}</td>
<td>{{ form_widget(form.description) }}</td>
<td class="error">{{ form_errors(form.description) }}</td>
</tr>
<tr>
<td>{{ form_label(form.url) }}</td>
<td>{{ form_widget(form.url) }}</td>
<td class="error">{{ form_errors(form.url) }}</td>
</tr>
<tr></tr>
<tr>{{ form_rest(form) }}</tr>
<tr>
<td></td><td><input type="submit" formnovalidate /></td>
<tr>
</table>
</div>
<br />
</form>
</div>
{% endblock maincolumn %}
{% block rightcolumn %}
<p>Utiliza el formulario para introducir una tarea nueva</p>
{% endblock rightcolumn %} |
{# src/curso/TaskBundle/Resources/views/Default/new2desplegado.html.twig #}
{% extends "cursoTaskBundle:Default:template-base-curso.html.twig" %}
{% block title %}
Insertar nueva tarea
{% endblock title %}
{% block header %}
<div id="header">
<div id="titulo-centro">
<h1>INSERTAR NUEVA TAREA</h1>
</div>
</div>
{% endblock header %}
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="/">HOME </a></li>
<li class="actual"><a href="/curso/template">Template</a></li>
<li class="last"><a href="/curso/new2">Nueva tarea</a></li>
</ul>
{% endblock breadcrumbs %}
{% block maincolumn %}
{% block message %}
{% endblock message %}
<div id="form-div" style="width: 800px; margin:auto; padding:10px;">
<form action="{{ path('cursoTaskBundle_task_new2') }}" method="post" {{ form_enctype(form) }}>
<div id="errores_form" class="error">
<!-- errores generales del formulario -->
{{ form_errors(form) }}
</div>
<div id="formcontent">
<table style="border-collapse:separate; border-spacing:1em;">
<tr>
<td>{{ form_label(form.task) }}</td>
<td>{{ form_widget(form.task) }}</td>
<td class="error">{{ form_errors(form.task) }}</td>
</tr>
<tr>
<td>{{ form_label(form.dueDate) }}</td>
<td>{{ form_widget(form.dueDate) }}</td>
<td class="error">{{ form_errors(form.dueDate) }}</td>
</tr>
<tr>
<td>{{ form_label(form.description) }}</td>
<td>{{ form_widget(form.description) }}</td>
<td class="error">{{ form_errors(form.description) }}</td>
</tr>
<tr>
<td>{{ form_label(form.url) }}</td>
<td>{{ form_widget(form.url) }}</td>
<td class="error">{{ form_errors(form.url) }}</td>
</tr>
<tr></tr>
<tr>{{ form_rest(form) }}</tr>
<tr>
<td></td><td><input type="submit" formnovalidate /></td>
<tr>
</table>
</div>
<br />
</form>
</div>
{% endblock maincolumn %}
{% block rightcolumn %}
<p>Utiliza el formulario para introducir una tarea nueva</p>
{% endblock rightcolumn %}
Now the one that shows all the tasks in a table: show.html.twig
:
Notice how the link to the edit is created!
{% extends "cursoTaskBundle:Default:new2desplegado.html.twig" %}
{% block title %}
Listado de tareas
{% endblock title %}
{% block header %}
<div id="header">
<div id="titulo-centro">
<h1>MOSTRAR TAREAS</h1>
</div>
</div>
{% endblock header %}
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="/">HOME </a></li>
<li class="actual"><a href="/curso/template">Curso</a></li>
<li class="last">Mostrar tareas</li>
</ul>
{% endblock breadcrumbs %}
{% block maincolumn %}
{% block message %}
{% if tasks is defined %}
<table style="border-spacing: 5px; margin-right: 5px; border-collapse: separate;">
<tr style="font-weight: bold;">
<td></td><!-- editar -->
<!--<td>ID</td>-->
<td>NOMBRE</td>
<td>FECHA</td>
<td>DESCRIPCIÓN</td>
<td>URL</td>
</tr>
{% for tarea in tasks %}
<tr style="font-size: 0.8em">
<td><a href=" {{ path('cursoTaskBundle_task_edit', { 'id' : tarea.id } ) }}" style="color:#A90641; font-size:0.9em; ">edit</a></td><!-- editar -->
<!--<td>{{ tarea.id }}</td>-->
<td>{{ tarea.task }}</td>
<td>{{ tarea.dueDate|date("m/d/Y") }}</td>
<td>{{ tarea.description }}</td>
<td>{{ tarea.url }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<p>No hay tareas. Puedes <a href="{{ path('cursoTaskBundle_task_new2') }}">Insertar una nueva tarea</a></p>
{% endif %}
{% endblock message %}
{% endblock maincolumn %}
{% block rightcolumn %}
{% endblock rightcolumn %} |
{% extends "cursoTaskBundle:Default:new2desplegado.html.twig" %}
{% block title %}
Listado de tareas
{% endblock title %}
{% block header %}
<div id="header">
<div id="titulo-centro">
<h1>MOSTRAR TAREAS</h1>
</div>
</div>
{% endblock header %}
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="/">HOME </a></li>
<li class="actual"><a href="/curso/template">Curso</a></li>
<li class="last">Mostrar tareas</li>
</ul>
{% endblock breadcrumbs %}
{% block maincolumn %}
{% block message %}
{% if tasks is defined %}
<table style="border-spacing: 5px; margin-right: 5px; border-collapse: separate;">
<tr style="font-weight: bold;">
<td></td><!-- editar -->
<!--<td>ID</td>-->
<td>NOMBRE</td>
<td>FECHA</td>
<td>DESCRIPCIÓN</td>
<td>URL</td>
</tr>
{% for tarea in tasks %}
<tr style="font-size: 0.8em">
<td><a href=" {{ path('cursoTaskBundle_task_edit', { 'id' : tarea.id } ) }}" style="color:#A90641; font-size:0.9em; ">edit</a></td><!-- editar -->
<!--<td>{{ tarea.id }}</td>-->
<td>{{ tarea.task }}</td>
<td>{{ tarea.dueDate|date("m/d/Y") }}</td>
<td>{{ tarea.description }}</td>
<td>{{ tarea.url }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<p>No hay tareas. Puedes <a href="{{ path('cursoTaskBundle_task_new2') }}">Insertar una nueva tarea</a></p>
{% endif %}
{% endblock message %}
{% endblock maincolumn %}
{% block rightcolumn %}
{% endblock rightcolumn %}
The view for showing the “Success” message is called success.html.twig
:
{% extends "cursoTaskBundle:Default:new2desplegado.html.twig" %}
{% block title %}
Tarea guardada
{% endblock title %}
{% block header %}
<div id="header">
<div id="titulo-centro">
<h1>Tarea guardada</h1>
</div>
</div>
{% endblock header %}
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="/">HOME </a></li>
<li class="actual"><a href="/curso/template">Template</a></li>
<li class="last">Tarea completada</li>
</ul>
{% endblock breadcrumbs %}
{% block maincolumn %}
{% block message %}
{{ message|raw }}
<br /><br />
<p>Utiliza los enlaces del menu para realizar una nueva tarea o visualizar las tareas existentes</p>
{% endblock message %}
{% endblock maincolumn %} |
{% extends "cursoTaskBundle:Default:new2desplegado.html.twig" %}
{% block title %}
Tarea guardada
{% endblock title %}
{% block header %}
<div id="header">
<div id="titulo-centro">
<h1>Tarea guardada</h1>
</div>
</div>
{% endblock header %}
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="/">HOME </a></li>
<li class="actual"><a href="/curso/template">Template</a></li>
<li class="last">Tarea completada</li>
</ul>
{% endblock breadcrumbs %}
{% block maincolumn %}
{% block message %}
{{ message|raw }}
<br /><br />
<p>Utiliza los enlaces del menu para realizar una nueva tarea o visualizar las tareas existentes</p>
{% endblock message %}
{% endblock maincolumn %}
The view associated with the “EDIT TASK X” is edit2desplegado.html.twig
:
{# src/curso/TaskBundle/Resources/views/Default/new2desplegado.html.twig #}
{% extends "cursoTaskBundle:Default:template-base-curso.html.twig" %}
{% block title %}
Modificar tarea
{% endblock title %}
{% block header %}
<div id="header">
<div id="titulo-centro">
<h1>MODIFICAR TAREA</h1>
</div>
</div>
{% endblock header %}
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="/">HOME </a></li>
<li class="actual"><a href="/curso/template">Template</a></li>
<li class="last">Editar tarea</li>
</ul>
{% endblock breadcrumbs %}
{% block maincolumn %}
{% block message %}
{% endblock message %}
<div id="form-div" style="width: 800px; margin:auto; padding:10px;">
<form action="{{ path('cursoTaskBundle_task_edit', { 'id' : id } ) }}" method="post" {{ form_enctype(form) }}>
<div id="errores_form" class="error">
<!-- errores generales del formulario -->
{{ form_errors(form) }}
</div>
<div id="formcontent">
<table style="border-collapse:separate; border-spacing:1em;">
<tr>
<td>{{ form_label(form.task) }}</td>
<td>{{ form_widget(form.task) }}</td>
<td class="error">{{ form_errors(form.task) }}</td>
</tr>
<tr>
<td>{{ form_label(form.dueDate) }}</td>
<td>{{ form_widget(form.dueDate) }}</td>
<td class="error">{{ form_errors(form.dueDate) }}</td>
</tr>
<tr>
<td>{{ form_label(form.description) }}</td>
<td>{{ form_widget(form.description) }}</td>
<td class="error">{{ form_errors(form.description) }}</td>
</tr>
<tr>
<td>{{ form_label(form.url) }}</td>
<td>{{ form_widget(form.url) }}</td>
<td class="error">{{ form_errors(form.url) }}</td>
</tr>
<tr></tr>
<tr>{{ form_rest(form) }}</tr>
<tr>
<td></td><td><input type="submit" formnovalidate /></td>
<tr>
</table>
</div>
<br />
</form>
</div>
{% endblock maincolumn %}
{% block rightcolumn %}
<p>Utiliza el formulario para editar la tarea nueva</p>
{% endblock rightcolumn %} |
{# src/curso/TaskBundle/Resources/views/Default/new2desplegado.html.twig #}
{% extends "cursoTaskBundle:Default:template-base-curso.html.twig" %}
{% block title %}
Modificar tarea
{% endblock title %}
{% block header %}
<div id="header">
<div id="titulo-centro">
<h1>MODIFICAR TAREA</h1>
</div>
</div>
{% endblock header %}
{% block breadcrumbs %}
<ul>
<li class"=first"><a href="/">HOME </a></li>
<li class="actual"><a href="/curso/template">Template</a></li>
<li class="last">Editar tarea</li>
</ul>
{% endblock breadcrumbs %}
{% block maincolumn %}
{% block message %}
{% endblock message %}
<div id="form-div" style="width: 800px; margin:auto; padding:10px;">
<form action="{{ path('cursoTaskBundle_task_edit', { 'id' : id } ) }}" method="post" {{ form_enctype(form) }}>
<div id="errores_form" class="error">
<!-- errores generales del formulario -->
{{ form_errors(form) }}
</div>
<div id="formcontent">
<table style="border-collapse:separate; border-spacing:1em;">
<tr>
<td>{{ form_label(form.task) }}</td>
<td>{{ form_widget(form.task) }}</td>
<td class="error">{{ form_errors(form.task) }}</td>
</tr>
<tr>
<td>{{ form_label(form.dueDate) }}</td>
<td>{{ form_widget(form.dueDate) }}</td>
<td class="error">{{ form_errors(form.dueDate) }}</td>
</tr>
<tr>
<td>{{ form_label(form.description) }}</td>
<td>{{ form_widget(form.description) }}</td>
<td class="error">{{ form_errors(form.description) }}</td>
</tr>
<tr>
<td>{{ form_label(form.url) }}</td>
<td>{{ form_widget(form.url) }}</td>
<td class="error">{{ form_errors(form.url) }}</td>
</tr>
<tr></tr>
<tr>{{ form_rest(form) }}</tr>
<tr>
<td></td><td><input type="submit" formnovalidate /></td>
<tr>
</table>
</div>
<br />
</form>
</div>
{% endblock maincolumn %}
{% block rightcolumn %}
<p>Utiliza el formulario para editar la tarea nueva</p>
{% endblock rightcolumn %}
Now the stylesheets (remember to put them into Resources\public\css\layout\
!)
reset.css
(compressed):
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}:focus{outline:0}ins{text-decoration:none}del{text-decoration:line-through}table{border-collapse:collapse;border-spacing:0} |
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}:focus{outline:0}ins{text-decoration:none}del{text-decoration:line-through}table{border-collapse:collapse;border-spacing:0}
mainStyle.css
.tt1 {background:#FF0000;}
.tt2 {background:#FF00FF;}
.tt3 {background:#FFFF00;}
html { }
body {font: 13px/1.5 Verdana, Arial, sans-serif; background:url(../_images/bck2.jpg) 50% 0 repeat-x;}
a:focus {outline: 1px dotted invert;}
a:link {color:#000; text-decoration:none;}
a:visited {color:#000; text-decoration:none;}
a:hover {color:#000; text-decoration:none;}
a:active {color:#000; text-decoration:none;}
#footer a:link {color:#666; text-decoration:none;}
#footer a:visited {color:#666; text-decoration:none;}
#footer a:hover {color:#666; text-decoration:none;}
#footer a:active {color:#666; text-decoration:none;}
hr {border-color: #ccc; border-style: solid; border-width: 1px 0 0; clear: both; height: 0;}
p { }
sup {position: relative;top: -3px;vertical-align: top;font-size: 80%;}
sub {position: relative;bottom: -5px;vertical-align: top;font-size: 80%;}
h1 {font-size: 25px;}
h2 {font-size: 23px;}
h3 {font-size: 21px;}
h4 {font-size: 19px;}
h5 {font-size: 17px;}
h6 {font-size: 15px;}
.xxsmall {font-size: 10px;}
.xsmall {font-size: 12px;}
.small {font-size: 14px;}
.medium {font-size: 16px;}
.large {font-size: 22px;}
.xlarge {font-size: 26px;}
.xxlarge {font-size: 32px;}
ol {list-style: decimal;}
ul {list-style: square;}
li {margin-left: 30px;}
p, dl, hr, h1, h2, h3, h4, h5, h6, ol, ul, pre, table, address, fieldset {margin-bottom: 20px;}
#wrapper {overflow:hidden; width:960px; margin:20px auto;}
html body * span.clear,html body * div.clear,html body * li.clear,html body * dd.clear{background:none;border:0;clear:both;display:block;float:none;font-size:0;list-style:none;margin:0;padding:0;overflow:hidden;visibility:hidden;width:0;height:0}
.margin-left {margin-left:20px;}
.margin-right {margin-right:20px;}
.margin-top {margin-top:20px;}
.margin-bottom {margin-bottom:20px;}
.margin-left-half {margin-left:10px;}
.margin-right-half {margin-right:10px;}
.margin-top-half {margin-top:10px;}
.margin-bottom-half {margin-bottom:10px;}
.margin-bottom-none {margin-bottom:0;}
img.centered {display:block;margin-left:auto;margin-right:auto;}
img.alignright {display: inline;}
img.alignleft {display: inline;}
.alignright {float:right;}
.alignleft {float:left;}
.bold {font-weight:bold;}
.italic {font-style:italic;}
.text-left {text-align:left;}
.text-right {text-align:right;}
.uppercase {text-transform:uppercase;}
.text-justify{text-align:justify;}
/*=================MAIN END==============*/
/* BREADCRUMBS! */
#breadcrumbs {margin-left:160px;}
#breadcrumbs ul li{display: inline; }
#breadcrumbs ul li:before{ content:"\00BB \0020";}
/*=================HEADER START==============*/
#header {width:960px;float:left; min-height: 80px;}
/*=================HEADER END==============*/
/*=================CONTENT START==============*/
#content {width:960px;float:left; padding-top:10px; padding-bottom: 10px;}
/*======LEFT COLUMN START======*/
#left-column {width:160px;float:left;}
#menu-sub {float:left;}
#menu-sub ul {list-style:none;}
#menu-sub ul li {font-size:16px;}
/*======LEFT COLUMN END======*/
/*======MAIN COLUMN START======*/
#main-column {width:630px;float:left;padding-right:10px;}
/*======MAIN COLUMN END======*/
/*======RIGHT COLUMN START======*/
#right-column {width:140px;float:left;padding-left:10px; padding-right:10px;}
/*======RIGHT COLUMN END======*/
/*=================CONTENT END==============*/
/*=================FOOTER START==============*/
#footer {width:960px;float:left;text-align:center;color:#666; min-height:30px; padding: 15px;}
/*=================FOOTER END==============*/ |
.tt1 {background:#FF0000;}
.tt2 {background:#FF00FF;}
.tt3 {background:#FFFF00;}
html { }
body {font: 13px/1.5 Verdana, Arial, sans-serif; background:url(../_images/bck2.jpg) 50% 0 repeat-x;}
a:focus {outline: 1px dotted invert;}
a:link {color:#000; text-decoration:none;}
a:visited {color:#000; text-decoration:none;}
a:hover {color:#000; text-decoration:none;}
a:active {color:#000; text-decoration:none;}
#footer a:link {color:#666; text-decoration:none;}
#footer a:visited {color:#666; text-decoration:none;}
#footer a:hover {color:#666; text-decoration:none;}
#footer a:active {color:#666; text-decoration:none;}
hr {border-color: #ccc; border-style: solid; border-width: 1px 0 0; clear: both; height: 0;}
p { }
sup {position: relative;top: -3px;vertical-align: top;font-size: 80%;}
sub {position: relative;bottom: -5px;vertical-align: top;font-size: 80%;}
h1 {font-size: 25px;}
h2 {font-size: 23px;}
h3 {font-size: 21px;}
h4 {font-size: 19px;}
h5 {font-size: 17px;}
h6 {font-size: 15px;}
.xxsmall {font-size: 10px;}
.xsmall {font-size: 12px;}
.small {font-size: 14px;}
.medium {font-size: 16px;}
.large {font-size: 22px;}
.xlarge {font-size: 26px;}
.xxlarge {font-size: 32px;}
ol {list-style: decimal;}
ul {list-style: square;}
li {margin-left: 30px;}
p, dl, hr, h1, h2, h3, h4, h5, h6, ol, ul, pre, table, address, fieldset {margin-bottom: 20px;}
#wrapper {overflow:hidden; width:960px; margin:20px auto;}
html body * span.clear,html body * div.clear,html body * li.clear,html body * dd.clear{background:none;border:0;clear:both;display:block;float:none;font-size:0;list-style:none;margin:0;padding:0;overflow:hidden;visibility:hidden;width:0;height:0}
.margin-left {margin-left:20px;}
.margin-right {margin-right:20px;}
.margin-top {margin-top:20px;}
.margin-bottom {margin-bottom:20px;}
.margin-left-half {margin-left:10px;}
.margin-right-half {margin-right:10px;}
.margin-top-half {margin-top:10px;}
.margin-bottom-half {margin-bottom:10px;}
.margin-bottom-none {margin-bottom:0;}
img.centered {display:block;margin-left:auto;margin-right:auto;}
img.alignright {display: inline;}
img.alignleft {display: inline;}
.alignright {float:right;}
.alignleft {float:left;}
.bold {font-weight:bold;}
.italic {font-style:italic;}
.text-left {text-align:left;}
.text-right {text-align:right;}
.uppercase {text-transform:uppercase;}
.text-justify{text-align:justify;}
/*=================MAIN END==============*/
/* BREADCRUMBS! */
#breadcrumbs {margin-left:160px;}
#breadcrumbs ul li{display: inline; }
#breadcrumbs ul li:before{ content:"\00BB \0020";}
/*=================HEADER START==============*/
#header {width:960px;float:left; min-height: 80px;}
/*=================HEADER END==============*/
/*=================CONTENT START==============*/
#content {width:960px;float:left; padding-top:10px; padding-bottom: 10px;}
/*======LEFT COLUMN START======*/
#left-column {width:160px;float:left;}
#menu-sub {float:left;}
#menu-sub ul {list-style:none;}
#menu-sub ul li {font-size:16px;}
/*======LEFT COLUMN END======*/
/*======MAIN COLUMN START======*/
#main-column {width:630px;float:left;padding-right:10px;}
/*======MAIN COLUMN END======*/
/*======RIGHT COLUMN START======*/
#right-column {width:140px;float:left;padding-left:10px; padding-right:10px;}
/*======RIGHT COLUMN END======*/
/*=================CONTENT END==============*/
/*=================FOOTER START==============*/
#footer {width:960px;float:left;text-align:center;color:#666; min-height:30px; padding: 15px;}
/*=================FOOTER END==============*/
And last one, colors.css
(compressed):
a{color:#A90641}a:hover{color:#A90641}a:visited{color:#A90641}a:active{color:#A90641} body{ background:#464646; color:#333;} #content{ color:#EEE; font-size: 0.8em;background-color: #343333;} #header{color:#FCFAD0;border-bottom:thick double #A90641;background:#111;}#footer{font-size:0.7em;border-top:thick double #A90641;background: #111;color:#5B605F;font-weight:bold;}#menu-sub a{font-size:0.8em; color:#A90641;}#menu-sub {padding-left:5px;}#menu-sub a:hover{font-size:0.8em; color:#CB2863;}#menu-sub a:visited{font-size:0.8em; color:#A90641;}#titulo-centro{margin:auto; width: 920px;padding:20px;text-align:center;}#breadcrumbs a{color:#A90641}.actual a{font-weight:bold;} |
a{color:#A90641}a:hover{color:#A90641}a:visited{color:#A90641}a:active{color:#A90641} body{ background:#464646; color:#333;} #content{ color:#EEE; font-size: 0.8em;background-color: #343333;} #header{color:#FCFAD0;border-bottom:thick double #A90641;background:#111;}#footer{font-size:0.7em;border-top:thick double #A90641;background: #111;color:#5B605F;font-weight:bold;}#menu-sub a{font-size:0.8em; color:#A90641;}#menu-sub {padding-left:5px;}#menu-sub a:hover{font-size:0.8em; color:#CB2863;}#menu-sub a:visited{font-size:0.8em; color:#A90641;}#titulo-centro{margin:auto; width: 920px;padding:20px;text-align:center;}#breadcrumbs a{color:#A90641}.actual a{font-weight:bold;}
And… that’s all, folks.
Please comment if you notice any bugs 🙂
Update:
Spanish readers might find this links interesting:
A bit outdated, but quite interesting, basic form tutorial and another, more advanced one, about understanding symfony form binding. This one also ispired me