Symfony for beginners – Multipage Controller

Un semplice esempio per creare un Controller Multipagina per gestire contenuti dinamici in un template .twig

1. app\Resources\views\base.html.twig


<!-- app\Resources\views\base.html.twig -->
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>{% block title %}Welcome to my Company{% endblock %}</title>
        {% block stylesheets %}{% endblock %}
        <link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
    </head>
    <body>
        {% block body %}{% endblock %}
        {% block javascripts %}{% endblock %}
    </body>
</html>

2. app\Resources\views\index.html.twig


{# app\Resources\views\index.html.twig #}

{% extends 'base.html.twig' %}

{% block body %}
<h1>This is one page</h1>
<strong>This is the page: {{pagetitle}}</strong>
<br>
{{navigationmenu | raw }}
<br>
<a href="#">Visit My company</a>
<br>
{{pagecontent}}
{% endblock %}

{% block stylesheets %}
<style>
    h1 { font-size: 36px; }
</style>
{% endblock %}

3. src\AppBundle\Controller\MyCompanyController.php


<?php
//src\AppBundle\Controller\MyCompanyController.php
namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;  // namespace for route
use Symfony\Component\HttpFoundation\Response;               // namespace for http render
use Symfony\Bundle\FrameworkBundle\Controller\Controller;    // to extend Controller

class MyCompanyController extends Controller
{
    // proprietà comuni
    // protected perchè non vogliamo che venga modificata dall'esterno
    protected $menu = '<strong>The Navigation Bar:</strong><br>'
            . '<a href="/">Home</a><br>'
            . '<a href="aboutus">About Us</a><br>'
            . '<a href="services">Services</a><br>'
            . '<a href="contactus">Contact Us</a>'
            ; 
    
     /**
    * @Route("/")
    */
    public function homeAction() // sempre suffisso ...Action
    {
        // send the variable to a .twig template
        return $this->render('index.html.twig', array(
            'navigationmenu' => $this->menu, //$this è la sintassi per usare le proprietà
            'pagetitle' => 'Home',
            'pagecontent' => 'Content of Home',
        ));
    }// END home ------------------------------------------------------------
    /**
    * @Route("/aboutus")
    */
    public function aboutUsAction() // sempre suffisso ...Action
    {
        
        $number = mt_rand(0, 100); // this is plain PHP
        // send the variable to a .twig template
        return $this->render('index.html.twig', array(
            'navigationmenu' => $this->menu,
            'pagetitle' => 'About Us',
            'pagecontent' => 'Content of About Us and a number RNG '. $number,
        ));
    }// END aboutus ----------------------------------------------------------
    /**
    * @Route("/services")
    */
    public function servicesAction() // sempre suffisso ...Action
    {
        // send the variable to a .twig template
        return $this->render('index.html.twig', array(
            'navigationmenu' => $this->menu,
            'pagetitle' => 'Services',
            'pagecontent' => 'Content of Services',
        ));
    }// END services ---------------------------------------------------------
    /**
    * @Route("/contactus")
    */
    public function contactUsAction() // sempre suffisso ...Action
    {
        // send the variable to a .twig template
        return $this->render('index.html.twig', array(
            'navigationmenu' => $this->menu,
            'pagetitle' => 'Contact Us',
            'pagecontent' => 'Content of Contact Us',
        )); 
    }// END contacUs ---------------------------------------------------------
    
}// END class MyCompanyController

Puntare il browser alla homepage a: http://localhost/symfonytest/first_test_symfony/web/

Come funziona?

1. MyCompanyController.php

a. creo una proprietà ‘protected’ perchè non voglio che sia modificabile dall’esterno, questo garantirà maggior robustezza al mio codice. Dentro a $menu vi è il menù di navigazione comune a tutte le pagine.

b. ogni pagina è un metodo con:

– un percorso @Route

– un nome del metodo chiaro che ci aiuta a identificare il suo compito.
Ogni metodo deve avere il suffisso Action()

– invio al template ‘index.html.twig’ di un array di variabili
Notare che ‘$this->menu’ è la sintassi corretta per recuperare la proprietà all’interno della funzione.

2. index.html.twig

– estende ‘base.html.twig’

– riceve le variabili come plain text {{pagetitle}}

– riceve le variabili come HTML {{navigationmenu | raw }}, notare che il dato è raw

By |PHP, Symfony, Web Design|Commenti disabilitati su Symfony for beginners – Multipage Controller

Symfony lezioni di base – Creare un Form come Classe

Nella lezione precedente abbiamo creato un form direttamente all’interno del controller, utilizzando lo schema:


class DefaultController extends Controller // estende la classe Controller di Symfony
{
	...
    
    public function newAction(Request $request)
   {
       ...

       // 1. creo i contenuti HTML del form
       $form = $this->createFormBuilder($task)

       ....

Il metodo ‘createFormBuilder()’ è utilizzato all’interno di ‘class DefaultController extends Controller’

Form come classe

Creare un form in una classe separata ci permette di riutilizzarlo più facilmente, lo schema di funzionanmento sarà

Il nostro controller invoca la classe contenente le istruzioni per creare il form: $form = $this->createForm(TaskType::class, $task);


public function newAction(Request $request)
   {
        ...

       // 1. creo i contenuti HTML del form
       // invia $task a TaskType.php classe TaskType
       $form = $this->createForm(TaskType::class, $task);

        ...

La Classe per creare il form TaskType.php:


...

class TaskType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('task')
            ->add('dueDate', null, array('widget' => 'single_text'))
            ->add('save', SubmitType::class)
...

Il codice completo

src/AppBundle/Controller/DefaultController.php


<?php

// src/AppBundle/Controller/DefaultController.php
namespace AppBundle\Controller;

use AppBundle\Entity\Task; // carica Task.php creato da me
use AppBundle\Form\TaskType; // carica TaskType.php creato da me

use Symfony\Component\HttpFoundation\Request; // capacità do renderizzare html render()

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;// NECESSARIO per utilizzare @Route

use Symfony\Bundle\FrameworkBundle\Controller\Controller; // il bundle controller Symfony per usare createForm()

class DefaultController extends Controller // deve estendere Controller
{
	/**
	* @Route("/form")
	*/
    
    public function newAction(Request $request)
   {
       // creo il nuovo oggetto 
       $task = new Task();
       // die("interrompi qui"); // debug

       // 1. creo i contenuti HTML del form
       // invia $task a TaskType.php classe TaskType
       $form = $this->createForm(TaskType::class, $task);
       
       // 3. riconosce che il form non è stato inviato e non fa nulla
       $form->handleRequest($request); 
       
       // 4. se il form è inviato AND valido
       if ($form->isSubmitted() && $form->isValid()) {
           // $form->getData() holds the submitted values
           // but, the original `$task` variable has also been updated
           $task = $form->getData();// ottieni i dati dal form

           // die ("interrompi qui 2");
           // ... perform some action, such as saving the task to the database
           // for example, if Task is a Doctrine entity, save it!
           // $em = $this->getDoctrine()->getManager();
           // $em->persist($task);
           // $em->flush();

           // alla fine fai redirect all'esterno 
           return $this->redirect('http://www.lucedigitale.com');
           
           // oppure verso una @Route di Symfony
           //return $this->redirectToRoute('homepage');
       }

       // 2. Il form viene creato e renderizzato
       return $this->render('default/new.html.twig', array(
           'form' => $form->createView(),
       ));
   }
}

src/AppBundle/Form/TaskType.php


<?php

// src/AppBundle/Form/TaskType.php
namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType; // form astratto
use Symfony\Component\Form\FormBuilderInterface; // buildForm()
use Symfony\Component\Form\Extension\Core\Type\SubmitType; // SubmitType::class

class TaskType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('task')
            ->add('dueDate', null, array('widget' => 'single_text'))
            ->add('save', SubmitType::class)
        ;
    }
}

src/AppBundle/Entity/Task.php


<?php

// src/AppBundle/Entity/Task.php
namespace AppBundle\Entity;

use Symfony\Component\Validator\Constraints as Assert; // serve per @Assert\...

class Task // dichiarazione esplicita dell'oggetto
{
    
    /**
     * @Assert\NotBlank()
     * @Assert\EqualTo("Andrea")
     */
    public $task;    // cose da fare
    
     /**
     * @Assert\NotBlank()
     * @Assert\Type("\DateTime")
     */
    protected $dueDate; // scadenza

    
    // NB metodi get e set obbligatori per permettere a 'Form component' di symfony di funzionare correttamente
    public function getTask() // ottieni le cose da fare
    {
        return $this->task; // assegna il valore che proviene dall'istanza $this->
    }

    public function setTask($task) // setta le cose gda fare
    {
        $this->task = $task;
    }

    public function getDueDate() // ottieni la scadenza
    {
        return $this->dueDate;
    }

    public function setDueDate(\DateTime $dueDate = null) // setta la scadenza
    {
        $this->dueDate = $dueDate;
    }
}

app/Resources/views/default/new.html.twig


{# app/Resources/views/default/new.html.twig #}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}

Come funziona?

0. al primo caricamento viene creato l’oggetto che contiene le mie variabili
$task = new Task();

1.
vengono creati i tag HTML per il form
$form = $this->createForm(TaskType::class, $task); -> punta alla Classe TaskType.php

Viene renderizzato il form render(‘default/new.html.twig’…

2. il metodo $form->handleRequest($request); rileva che il form non è stato inviato e non fa nulla

3. quando premo ‘submit’
– $form->handleRequest($request); ritorna TRUE
– i dati vengono salvati in $form e aggiornati in $task

a)
– $form viene controllato
– se non sono validi && $form->isValid()) { -> in realtà è una scorciatoia che significa $task->isValid())
– viene automaticamente renderizzata di nuovo la pagina con gli errori di validazione

b)
– $form viene controllato
– se sono validi && $form->isValid()) {
– viene inviata la richiesta POST alla pagina di provenieneza
– interrompe lo script con return facendo un redirect ad un’altra pagina, ad esempio di ringraziamento

NB: il redirect non darà la possibilità all’utente di fare “Refresh nel browser ed inviare di nuovo il form

Bibliografia:
symfony.com/doc/current/forms.html – Creating Form Classes

By |PHP, Symfony, Web Design|Commenti disabilitati su Symfony lezioni di base – Creare un Form come Classe

Form Inside Controller – Oggetto Render Validazione

Il Form component per Symfony è un componente standalone che può essere utilizzato anche al di fuori di Symfony.

In questa lezione creeremo un form direttamente all’interno di un Controller:


class DefaultController extends Controller // estende la classe Controller di Symfony
{
	...
    
    public function newAction(Request $request)
   {
       ...

       // 1. creo i contenuti HTML del form
       $form = $this->createFormBuilder($task)

       ....

Il metodo ‘createFormBuilder()’ è utilizzato all’interno di ‘class DefaultController extends Controller’

Form con Dummy Data

1. Creare in src/AppBundle/Entity/Task.php


<?php

/// src/AppBundle/Entity/Task.php
namespace AppBundle\Entity;

class Task // dichiarazione esplicita dell'oggetto
{
    // proprietà o variabili non accessibile dall'esterno della classe
    protected $task;    // cose da fare
    protected $dueDate; // scadenza

    
    // NB metodi get e set obbligatori per permettere a 'Form component' di symfony di funzionare correttamente
    public function getTask() // ottieni le cose da fare
    {
        return $this->task; // assegna il valore che proviene dall'istanza $this->
    }

    public function setTask($task) // setta le cose gda fare
    {
        $this->task = $task;
    }

    public function getDueDate() // ottieni la scadenza
    {
        return $this->dueDate;
    }

    public function setDueDate(\DateTime $dueDate = null) // setta la scadenza
    {
        $this->dueDate = $dueDate;
    }
}

2. Creare in src/AppBundle/Controller/DefaultController.php


<?php

// src/AppBundle/Controller/DefaultController.php
namespace AppBundle\Controller;

use AppBundle\Entity\Task; // carica Task.php creato da me
use Symfony\Bundle\FrameworkBundle\Controller\Controller; // il bundle controller Symfont
use Symfony\Component\HttpFoundation\Request; // capacità do renderizzare html
use Symfony\Component\Form\Extension\Core\Type\TextType; // form di Symfony
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;// NECESSARIO per utilizzare @Route

class DefaultController extends Controller // estende la classe Controller di Symfony
{
	/**
	* @Route("/form")
	*/
    public function newAction(Request $request) // metodo
    {
        // Utilizzo della classe Task di Task.php per creare l'oggetto $task INIZIO -> crea $task
        $task = new Task();// creo un oggetto istanziando la classe Task
        $task->setTask('Write a blog post'); // assegno $task, le cose da fare
        $task->setDueDate(new \DateTime('tomorrow')); // setta la scadenza
        // Utilizzo della classe Task di Task.php per creare l'oggetto $task FINE

        // Creazione del form utilizzando le classi di Symfony INIZIO -> crea $form
        $form = $this->createFormBuilder($task)// invia al metodo createFormBuilder l'oggetto $task con tutte i dati
            // istruzioni per creare i TAG HTML INIZIO
            ->add('task', TextType::class)// invia al metodo add() assegnando la propietà 'task' di Task.php e la variabile statica 'TextType::class' che indica un campo di testo
            ->add('dueDate', DateType::class)// come sopra
            ->add('save', SubmitType::class, array('label' => 'Create Post'))// come sopra con aggiunta della label
            // istruzioni per creare i TAG HTML FINE
            ->getForm(); // questo metodo di Symfony restituisce il form
        // Creazione del form utilizzando le classi di Symfony FINE

        // ivia l'istruzione al template .twig inviando $form
        // la risposta finale è invio al metodo render() - template.twig - form - $form
        return $this->render('default/new.html.twig', array(
            'form' => $form->createView(),
        ));
    }
}

2. Creare in app/Resources/views/default/new.html.twig


{# app/Resources/views/default/new.html.twig #}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}

Puntare il browser su: http://localhost/symfonytest/first_test_symfony/web/form

Come funziona?
Si avvia DefaultController.php:
1. Crea l’oggetto $task instanziando in Task.php la class Task
2. Crea l’oggetto $form con il metodo createFormBuilder() di Symfony
3. Renderizza il form inviandolo al template ,twig con il metodo render() di Symfony

NB: – $task = new Task(); – sono dummy data – dati di esempio!!!

Form senza Dummy Data

Ripuliamo dai dati generati come esempio matenendo solo il form


<?php

// src/AppBundle/Controller/DefaultController.php
namespace AppBundle\Controller;

use AppBundle\Entity\Task; // carica Task.php creato da me
use Symfony\Bundle\FrameworkBundle\Controller\Controller; // il bundle controller Symfont
use Symfony\Component\HttpFoundation\Request; // capacità do renderizzare html
use Symfony\Component\Form\Extension\Core\Type\TextType; // form di Symfony
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;// NECESSARIO per utilizzare @Route

class DefaultController extends Controller // estende la classe Controller di Symfony
{
	/**
	* @Route("/form")
	*/
    
    public function newAction(Request $request)
   {
       // creo il nuovo oggetto 
       $task = new Task();
       // die("interrompi qui"); // debug

       // 1. creo i contenuti HTML del form
       $form = $this->createFormBuilder($task)
           ->add('task', TextType::class) // il nome delle varibili è lo stesso di Task.php
           ->add('dueDate', DateType::class)
           ->add('save', SubmitType::class, array('label' => 'Create Task'))
           ->getForm();
       
       // 3. riconosce che il form non è stato inviato e non fa nulla
       $form->handleRequest($request); 
       
       // 4. se il form è inviato AND valido
       if ($form->isSubmitted() && $form->isValid()) {
           // $form->getData() holds the submitted values
           // but, the original `$task` variable has also been updated
           $task = $form->getData();// ottieni i dati dal form

           // die ("interrompi qui 2");
           // ... perform some action, such as saving the task to the database
           // for example, if Task is a Doctrine entity, save it!
           // $em = $this->getDoctrine()->getManager();
           // $em->persist($task);
           // $em->flush();

           // alla fine fai redirect all'esterno 
           return $this->redirect('http://www.lucedigitale.com');
           
           // oppure verso una @Route di Symfony
           //return $this->redirectToRoute('homepage');
       }

       // 2. Il form viene creato e renderizzato
       return $this->render('default/new.html.twig', array(
           'form' => $form->createView(),
       ));
   }
}

Puntare il browser su: http://localhost/symfonytest/first_test_symfony/web/form

Come funziona?

0. al primo caricamento viene creato l’oggetto che contiene le mie variabili
$task = new Task();

1.
vengono creati i tag HTML per il form
$form = $this->createFormBuilder($task)

Viene renderizzato il form render(‘default/new.html.twig’…

2. il metodo $form->handleRequest($request); rileva che il form non è stato inviato e non fa nulla

3. quando premo ‘submit’
– $form->handleRequest($request); ritorna TRUE
– i dati vengono salvati in $form e aggiornati in $task

a)
– $form viene controllato
– se non sono validi && $form->isValid()) {
– viene automaticamente renderizzata di nuovo la pagina con gli errori di validazione

b)
– $form viene controllato
– se sono validi && $form->isValid()) {
– viene inviata la richiesta POST alla pagina di provenieneza
– interrompe lo script con return facendo un redirect ad un’altra pagina, ad esempio di ringraziamento

NB: il redirect non darà la possibilità all’utente di fare “Refresh nel browser ed inviare di nuovo il form

Validazione

Come visto sopra $form->isValid() è una scorciatoia per scrivere $task->isValid()
Il controllo di validazione quindi verrà effettuato su direttamente sull’oggetto e non sul form come si fa di solito in HTML

Modifichiamo Task.php che contiene il nostro oggetto:


<?php

/// src/AppBundle/Entity/Task.php
namespace AppBundle\Entity;

use Symfony\Component\Validator\Constraints as Assert; // serve per @Assert\...

class Task // dichiarazione esplicita dell'oggetto
{
    
    /**
     * @Assert\NotBlank()
     * @Assert\EqualTo("Andrea")
     */
    public $task;    // cose da fare
    
     /**
     * @Assert\NotBlank()
     * @Assert\Type("\DateTime")
     */
    protected $dueDate; // scadenza

    
    // NB metodi get e set obbligatori per permettere a 'Form component' di symfony di funzionare correttamente
    public function getTask() // ottieni le cose da fare
    {
        return $this->task; // assegna il valore che proviene dall'istanza $this->
    }

    public function setTask($task) // setta le cose gda fare
    {
        $this->task = $task;
    }

    public function getDueDate() // ottieni la scadenza
    {
        return $this->dueDate;
    }

    public function setDueDate(\DateTime $dueDate = null) // setta la scadenza
    {
        $this->dueDate = $dueDate;
    }
}

Notare:

– l’utilizzo del namspace

use Symfony\Component\Validator\Constraints as Assert;

– la notazione per la validazione:


     /**
     * @Assert\NotBlank()
     * @Assert\EqualTo("Andrea")
     */

Per $task verrà accettato solamente un campo non vuoto ed uguale ad “Andrea”
Se tento di inviare un campo vuoto o diverso da “Andrea” sarà restituito il controllo di validazione

Si può consultare la lista completa dei controlli di validazione a:
symfony.com/doc/current/validation.html

Bibliografia:
symfony.com/doc/current/forms.html
symfony.com/doc/current/validation.html

By |PHP, Symfony, Web Design|Commenti disabilitati su Form Inside Controller – Oggetto Render Validazione

Tutorial Symfony – Redirecting

Il redirectig ci permette di reindirizzare il browser verso una nuova pagina.

In PHP classico utilizziamo:


// redirect verso pagina interna
header("location: /nuova-pagina.php");
exit; // serve per interrompere lo script dopo il cambio di pagina o PHP darà ERRORE

// redirect verso una risorsa esterna al sito
header("location: http://www.sito.it/pagina.php");
exit;

In Symfony utilizzeremo invece:


public function indexAction()
{
    // la funzione fa qualcosa

    // redirect externally
    return $this->redirect('http://symfony.com/doc');

    // la parte qui sotto non verrà eseguita perchè ho fatto return
}

In symfony invocheremo i metodi:

redirect(): per i link esterni
redirectToRoute(): per le pagine interne definite da @Route


public function indexAction()
{
    // redirect to the "homepage" route
    return $this->redirectToRoute('homepage');

    // do a permanent - 301 redirect - Moved Permanently
    // consente di spostare un dominio o una pagina ad un altro indirizzo 
    // senza perdere il potere e il posizionamento acquisito dalla vecchia pagina.
    return $this->redirectToRoute('homepage', array(), 301);

    // redirect to a route with parameters
    return $this->redirectToRoute('blog_show', array('slug' => 'my-page'));

    // redirect externally
    return $this->redirect('http://symfony.com/doc');
}

Bibliografia:
symfony.com/doc/current/controller.html

By |PHP, Symfony, Web Design|Commenti disabilitati su Tutorial Symfony – Redirecting

Symfony for Beginners – Send var to Template

How to passing data from a page to a .twig Template

1. Create in src\AppBundle\Controller\LuckyController.php


<?php
// src/AppBundle/Controller/LuckyController.php
namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\Controller; // to extend Controller

class LuckyController extends Controller // extends Controllers of Symfony
{
    /**
     * @Route("/lucky/number")
     */
    public function numberAction() // my function
    {
        $number = mt_rand(0, 100); // random PHP function
        
        // send the variable to a .twig template
        return $this->render('lucky/number.html.twig', array(
            'number' => $number,
        ));
    }
}

2. Create in app\Resources\views\lucky\number.html.twig


{# app/Resources/views/lucky/number.html.twig #}

<h1>Your lucky number is {{ number }}</h1>

NOTICE:

a. The namespace to exted standard Controller of Symfony:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

b. The class have to extend the Controller namespace:
class LuckyController extends Controller

c. render using lucky/number.html.twig the array key ‘number’ with value $number
return $this->render(‘lucky/number.html.twig’, array(
‘number’ => $number,

d. the template receive the value of number

<h1>Your lucky number is {{ number }}</h1>

{{ number }} -> this is the syntax of .twig to get the value sent by public function numberAction()

{# app/Resources/views/lucky/number.html.twig #} -> this is a comment only in .twig syntax

By |PHP, Symfony, Web Design|Commenti disabilitati su Symfony for Beginners – Send var to Template