Tag Archives: Views

Oracle: guess the query of a view [SOLVED]

Some time ago, someone at my work created a new View in our Oracle database called AUTORESUZ (notice the capitals!) and I wanted to know how this view was defined, this is, the query that lies under it.

You can list all the views defined at your Oracle database by having a look at all_views table which stores the following information of each view:

SQL> DESC all_views;
 Name					   NULL?    TYPE
 ----------------------------------------- -------- ----------------------------
 OWNER					   NOT NULL VARCHAR2(30)
 VIEW_NAME				   NOT NULL VARCHAR2(30)
 TEXT_LENGTH					    NUMBER
 TEXT						    LONG
 TYPE_TEXT_LENGTH				    NUMBER
 TYPE_TEXT					    VARCHAR2(4000)
 OID_TEXT_LENGTH				    NUMBER
 OID_TEXT					    VARCHAR2(4000)
 VIEW_TYPE_OWNER				    VARCHAR2(30)
 VIEW_TYPE					    VARCHAR2(30)
 SUPERVIEW_NAME 				    VARCHAR2(30)

The query information is stored in “text” row. So, let’s retrieve the query that our AUTORESUZ has defined:

SQL> SELECT text FROM all_views WHERE view_name = 'AUTORESUZ';
 
TEXT
----------
SELECT a1.

OMFG! The query seems to be there, but it is truncated…

In order to view the full query, you must set long with a value greater that text’s length. Like this:

SQL> SELECT text_length FROM all_views WHERE view_name = 'AUTORESUZ';
 
TEXT_LENGTH
-----------
	369
 
SQL> SELECT text FROM all_views WHERE view_name = 'AUTORESUZ';
 
TEXT
----------
SELECT a1.
 
SQL> SET long 369
SQL> SELECT text FROM all_views WHERE view_name = 'AUTORESUZ';         
 
TEXT
--------------------------------------------------------------------------------
SELECT a1.rec_key AS arecord,
  REGEXP_REPLACE(a2.rec_data,'^\|a(.*)','\1') AS nipuz,
  REGEXP_REPLACE(REGEXP_REPLACE(REGEXP_REPLACE(a1.rec_data,'^\|a(.*)\|6\(UZ.*','
\1'), '(.*)\|c(.*)','\1'), '(.*),\|d(.*)','\1') AS autoruz
 
 FROM var_fields2 a1,  var_fields2 a2
 WHERE a1.rec_key LIKE 'a%' AND a1.MARC_TAG='100' AND
  (a1.rec_key=a2.rec_key AND a2.MARC_TAG='090')

Drupal 7: Path breadcrumbs in Views page [SOLVED]

Path breadcrumbs module allows you to easily add breadcrumbs to your Drupal site. The module lacks of documentation, but they offer this image as an example:

path_breadcrumbs

And there is a videotutorial as well.

The above show how to configure breadcrumbs in nodes, but… how to display breadcrumbs in Views pages?

This struggled me for a while, because I was taking the (limited) instructions too literally.

To create a breadcrumb to a views page display that has a path like “/path/to/my-view” just use that as the path (as it isn’t an alias). To know the path, go to your view and edit it (admin/structure/views/view/VIEWNAME/edit) and refer to the Page Settings – Path value.

Also, leave the “Arguments” and “Selection rules” empty, then setup your breadcrumbs as you did with nodes.

Let’s see an example. First, the path to the view:

Path breadcrumbs in views

Path breadcrumbs in views

And the path breadcrumbs configuration:

drupal 7 Path breadcrumbs in views

drupal 7 Path breadcrumbs in views

And here is the resulting breadcrumb. Remember that your theme’s page.tpl.php must print $breadcrumb or you will not see breadcrumbs at all…

path_breadcrumbs_in_views_page_2

Symfony: create and update an Entity using doctrine [FULL EXAMPLE]

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

… 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;
    }
}

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"

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

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: - }

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&eacute; 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 %}
&copy;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 %}

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&Oacute;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 %}

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 %}

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}

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==============*/

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;}

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

WordPress WP-Postviews en español [RESUELTO]

El plugin el plugin wp-postviews de wordpress permite mostrar en tu theme el número de lecturas de un determinado post, utilizando la función the_views();.

Si queréis añadir esta información a vuestros posts, podréis hacerlo con una línea del tipo:

// OJO! Dentro de 'the loop'
(leido <?php if(function_exists('the_views')) { the_views(); } ?>)

Y esto mostrará algo del tipo:
Leido 25 views

Nosotros queremos que el texto ‘views’ se muestre en español.

Para ello editamos /wp-content/plugins/wp-postviews/wp-postviews.php y buscamos este código:

### Function: Display The Post Views
function the_views($display = true, $prefix = '', $postfix = '', $always = false) {
	$post_views = intval(post_custom('views'));
	$views_options = get_option('views_options');
	if ($always || should_views_be_displayed($views_options)) {
		$output = $prefix.str_replace('%VIEW_COUNT%', number_format_i18n($post_views), $views_options['template']).$postfix;
		if($display) {
			echo apply_filters('the_views', $output);
		} else {
			return apply_filters('the_views', $output);
		}
	}
	elseif (!$display) {
		return '';
	}
}

Y lo cambiamos a esto:

### Function: Display The Post Views
function the_views($display = true, $prefix = '', $postfix = '', $always = false) {
	$post_views = intval(post_custom('views'));
	$views_options = get_option('views_options');
	if ($always || should_views_be_displayed($views_options)) {
		$output = $prefix.str_replace('%VIEW_COUNT%', number_format_i18n($post_views), $views_options['template']).$postfix;
		// Added the following line to change from 'views' to 'veces' -----------
		$output = str_replace('views','veces',$output);
                // ------------------------------------------------------------------
		if($display) {
			echo apply_filters('the_views', $output);
		} else {
			return apply_filters('the_views', $output);
		}
	}
	elseif (!$display) {
		return '';
	}
}

¡Y ya está!