Modern Web Development I Web Application Frameworks Data: 12/12/2013 Docente: Valerio Panzica La Manna Politecnico di Milano [email protected] www.webmoderno.wordpress.com © copyright CEFRIEL- Valerio Panzica La Manna -Milano-Italia- 2013_ Tutti i diritti riservati PYTHON AND DJANGO 2 Introduzione n n n n Django è un web application framework open-source che utilizza il linguaggio Python. Come Rails Django segue il paradigma MVC. Caratteristiche principali: – Architettura a componenti: • Riutilizzabile – Prototipazione rapida – DRY Molto utilizzato – Pinteresest – Instagram – Mozilla 3 © 2007 - CEFRIEL Componenti Principali n Model – Object-relational mapper tra database relazionali e classi python (data model) n View – Web Templating Systems – Basato sul concetto di ereditarietà n Controller – Delega le richieste sulla base di espressioni regolari n Stand-alone web server – per sviluppo e testing n n n Sistema di serializzazione e validazione dei form Framework di caching Built-in unit test framework 4 Applicazioni di default intergrate n n Sistema di autenticazione Sistema per l’interfaccia lato admin – Assente di default in Rails (ma integrabile tramite gem) n n n Sistema per la gestione dei commenti Generazione di sitemaps Protezione dai tipici attacchi web – SQL Injection – Cross-site scripting – Password cracking n Framework per la creazione di applicazioni GIS 5 Creare un progetto django-admin.py startproject mysite n Struttura del progetto creato – – – – – – n manage.py Utility per gestire il progetto mysite la vera e propria cartella di progetto mysite/__init__.py file vuoto che identifica la cartella come package mysite/settings.py per le configurazioni mysite/urls.py per la specifica del dispatching mysite/wsgi.py entry-point per web-servers compatibili con wsgi (protocollo tra server e Python) Lancio del server (porta del server opzionale) python manage.py runserver 8000 6 setting.py (Database) n Supporto built-in ai database: – – – – n SQLLite (default) PostGresSQL MySQL Oracle Configurazione – ENGINE: nome del package per il binding • Es: django.backends.sqlite3 – NAME: nome del database • Nel Caso di SQLLite path del file 7 settings.py (gestione delle app) n n INSTALLED_APPS contiene il nome di tutte le applicazioni Django da includere nel progetto. Default – – – – – – django.contrib.admin (pannello di amministrazione) django.contrib.auth (sistema di autenticazione) django.contrib.contenttypes (framework per la gestione dei tipi) django.contrib.sessions (sessioni) django.contrib.messages (framework per i messaggi) django.contrib.staticfiles (gestione file statici: immagini, css..) 8 syncdb n n n n python manage.py syncdb Il comando verifica il contenuto di INSTALLED_APPS e crea tutte le tabelle necessarie al lancio delle applicazioni. Es: Tra le applicazioni di default l’applicazione di auth richiede la creazione di tabelle. Lo stesso comando viene utilizzato per la generazione delle tabelle relative al modello del progetto. 9 Creiamo un app polls n n n n n Django distingue progetti da app. Una app è un modulo con funzionalità specifiche. Un progetto è composto da diverse app. La stessa app può essere utilizzata in più progetti Procedura: – la app viene creata all’esterno di mysite (allo stesso livello di manage.py) – questo ci permette di importarla tra le INSTALLED_APP e utilizzarla in mysite. n Comando: python manage.py startapp polls 10 Struttura di una app n polls/ – – – – __init__.py admin.py models.py file che contiene tutte le classi dei modelli views.py 11 models.py from django.db import models class Poll(models.Model): #ogni classe eredita da models.Model question = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') class Choice(models.Model): poll = models.ForeignKey(Poll) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) 12 Aggiungiamo polls in mysite/settings.py INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'polls', ) n n creiamo le tabelle python manage.py syncdb 13 Console Interattiva n n E’ possibile testare i propri modelli e le API di Django tramite shell interattiva. python manage.py shell >>> from polls.models import Poll, >>> Poll.objects.all() [] >>> from django.utils import timezone >>> p = Poll(question="What's new?", pub_date=timezone.now()) >>> p.save() >>> p.id 1 >>> p.question "What's new?” >>> p.question = "What's up?" >>> p.save() >>> Poll.objects.all() [<Poll: Poll object>] 14 Specificare metodi nel modello n Il modello non contiene solo i campi dei dati, ma anche operazioni su esse. import datetime from django.utils import timezone # ... class Poll(models.Model): # ... def was_published_recently(self): return self.pub_date >= timezone.now() datetime.timedelta(days=1) 15 Pannello di Amministrazione n n n n Il pannello di admin (l’app associata) è presente di default nel progetto. Raggiungibile da browser all’url ../admin/ Permette la gestione dei modelli Configurare admin per includere polls – Modifichiamo il file polls/admin.py from django.contrib import admin from polls.models import Poll #personalizzazione di admin class PollAdmin(admin.ModelAdmin): fieldsets = [ (None, {'fields': ['question']}), ('Date information', {'fields': ['pub_date']}), ] admin.site.register(Poll, PollAdmin) 16 Views n 1. 2. Procedura per la creazione di una view: All’interno di views.py dell’app definiamo i metodi che specificano cosa visualizzare. Associamo un url al metodo 1. Creiamo un nuovo file polls/urls.py 2. Specifichiamo il pattern dell’url e il suo mapping con il metodo in views.py 3. Nel progetto importiamo i mapping specificati per l’app 17 Primo esempio di views n All’interno di views.py dell’app definiamo i metodi che specificano cosa visualizzare. from django.http import HttpResponse def index(request): return HttpResponse("Hello, world. You're at the poll index.") n n ogni metodo ha come parametro la richiesta ritorna una HttpResponse 18 Primo esempio di views n Associamo un url al metodo – Creiamo un nuovo file polls/urls.py – Specifichiamo il mapping tra url e metodo from django.conf.urls import patterns, url from polls import views urlpatterns = patterns('', url(r'^$', views.index, name='index') n ) ogni metodo ha come parametro la richiesta 19 Primo esempio di views n Nel progetto (mysite/urls.py) importiamo i mapping specificati per l’app from django.conf.urls import patterns, include, url from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', url(r'^polls/', include('polls.urls')), url(r'^admin/', include(admin.site.urls)), ) 20 la funzione url() parametri n regex – – – – n espressione regolare che definisce il pattern dell’url da mappare. Il matching viene fatto in sequenza sui file urls.py Il primo pattern è quello associato. Il pattern è sull’URL non sul metodo HTTP view – nome della funzione della view da associare n name – associa un nome all’URL 21 Parametri nella richiesta (views.py) def detail(request, poll_id): return HttpResponse("You're looking at poll %s." % poll_id) def results(request, poll_id): return HttpResponse("You're looking at the results of poll %s." % poll_id) def vote(request, poll_id): return HttpResponse("You're voting on poll %s." % poll_id) 22 specifica parametri nel pattern from django.conf.urls import patterns, url from polls import views urlpatterns = patterns('', # ex: /polls/ url(r'^$', views.index, name='index'), # ex: /polls/5/ url(r'^(?P<poll_id>\d+)/$', views.detail, name='detail'), # ex: /polls/5/results/ url(r'^(?P<poll_id>\d+)/results/$', views.results, name='results'), # ex: /polls/5/vote/ url(r'^(?P<poll_id>\d+)/vote/$', views.vote, name='vote'), ) 23 Template n n E’ possibile associare template alle view In Django si preferisce separare i template per ogni app – Diversamente da Rails dove sono tutti insieme nella cartella view n Es:polls/index.html {% if latest_poll_list %} <ul> {% for poll in latest_poll_list %} <li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li> {% endfor %} </ul> {% else %} <p>No polls are available.</p> {% endif %} 24 Rendering del template n Modifichiamo views.py per visualizzare il template from django.http import HttpResponse from django.template import RequestContext, loader from polls.models import Poll def index(request): latest_poll_list = Poll.objects.order_by('-pub_date')[:5] template = loader.get_template('polls/index.html') context = RequestContext(request, { 'latest_poll_list': latest_poll_list, }) return HttpResponse(template.render(context)) n context associa un oggetto a un elemento del template. 25 TESTING IN DJANGO 26 Testing in Django n Potremmo testare la nostra applicazione tramite la shell – Verificare che i modelli e le validazioni sui campi vanno a buon fine. – Eseguire i metodi dei modelli e delle view. n Questo non è sufficiente – Nel contesto di uno sviluppo di applicazioni complesse molti componenti (classi, modelli, views) interagiscono tra di loro. – In un linguaggio come Python non siamo supportati dal compilatore – E se il codice evolve? Nuovi requisiti e funzionalità devono essere aggiunte? n E’ quindi necessario un approccio al testing sistematico e automatico. – Sistematico: TDD – Automatico: framework di testing 27 © 2007 - CEFRIEL Perché un testing sistematico n Riduce i tempi di sviluppo. – Un cambiamento del codice richiede allo sviluppatore di verificare manualmente che tutto funzioni come previsto. – Questo procedimento si ripete ad ogni cambiamento. n I test non solo identifica gli errori: li previene. – L’obiettivo di verificare manualmente che “tutto funzioni” non è preciso. – Scrivendo i tests si obbliga lo sviluppatore a pensare in maniera precisa quale è il comportamento atteso. n Migliora lo sviluppo in team – La modifica del codice da parte di un altro membro del team può far fallire dei test. – I test documentano l’uso corretto del codice scritto. 28 Esempio import datetime from django.utils import timezone # ... class Poll(models.Model): # ... def was_published_recently(self): return self.pub_date >= timezone.now() datetime.timedelta(days=1) n Il metodo ritorna true se la data di pubblicazione è successiva a ieri. 29 Esempio import datetime from django.utils import timezone # ... class Poll(models.Model): # ... def was_published_recently(self): return self.pub_date >= timezone.now() datetime.timedelta(days=1) n n Il metodo ritorna true se la data di pubblicazione è successiva a ieri. Ma anche se pub_date viene settato ad una data futura 30 Creazione di un test n I test sono inseriti in tests.py dell’app import datetime from django.utils import timezone from django.test import TestCase from polls.models import Poll class PollMethodTests(TestCase): def test_was_published_recently_with_future_poll(self): future_poll = Poll(pub_date=timezone.now() + datetime.timedelta(days=30)) self.assertEqual(future_poll.was_published_recently(), False) n Un test è una classe che eredita da TestCase 31 Esecuzione dei test n Comando: python manage.py test polls n Cerca tutti i test all’interno di tests.py in polls Se trova una classe che eredita da TestCase Esegue tutti i metodi che iniziano con la parola test n Fix del bug: n n def was_published_recently(self): now = timezone.now() return now - datetime.timedelta(days=1) <= self.pub_date < now 32 Testare La View n La parte critica e specifica delle applicazioni web è l’interazione con gli utenti. – Un bug in questa interazione è direttamente visibile all’utente. n n n Il testing unitario dei modelli non è sufficiente. Django offre un insieme di tool per il testing di questa interazione. Test Client: simula il comportamento dell’utente che interagische con la view. 33 Test client da shell >>> from django.test.utils import setup_test_environment >>> setup_test_environment() n n setup_test_environment() permette di analizzare attributi specifici della view (es. gli attributi di context) non crea un nuovo database – lavora sul database reale. >>> from django.test.client import Client >>> client = Client() n crea l’oggetto Client >>> from django.test.client import Client >>> client = Client() >>> response = client.get('/') >>> response.status_code 404 34 Test client da shell (2) >>> from django.core.urlresolvers import reverse >>> response = client.get(reverse('polls:index')) >>> response.status_code 200 >>> response.content '\n\n\n <p>No polls are available.</p>\n\n’ >>> from polls.models import Poll >>> from django.utils import timezone >>> p = Poll(question="Who is your favorite Beatle?", pub_date=timezone.now()) >>> p.save() >>> response = client.get('/polls/') >>> response.content '\n\n\n <ul>\n \n <li><a href="/polls/1/">Who is your favorite Beatle?</a></li>\n \n </ul>\n\n' >>> response.context['latest_poll_list'] [<Poll: Who is your favorite Beatle?>] 35 Testing della view n n in tests.py di polls creiamo un metodo create_poll per la creazione di nuovi oggetti poll def create_poll(question, days): return Poll.objects.create(question=question, pub_date=timezone.now() + datetime.timedelta(days=days)) n questo metodo non viene eseguito come test perché il nome del metodo non inizia con test 36 PollViewTests class PollViewTests(TestCase): def test_index_view_with_no_polls(self): response = self.client.get(reverse('polls:index')) self.assertEqual(response.status_code, 200) self.assertContains(response, "No polls are available.") self.assertQuerysetEqual(response.context['latest_poll_list'], []) def test_index_view_with_a_past_poll(self): create_poll(question="Past poll.", days=-30) response = self.client.get(reverse('polls:index')) self.assertQuerysetEqual( response.context['latest_poll_list'], ['<Poll: Past poll.>'] ) 37 Altri Tipologie di Test n n Django permette di integrare altri componenti utili per il testing. coverage.py – copertura: misura della porzione di codice coperta dai test – Identificazione di Dead Code (codice mai utilizzato) n Selenium – framework di testing “in-browser” – testa il modo in cui la pagina html è effettivamente renderizzata sul browser. – permette anche il testing del javascript associato alla pagina 38 PANORAMICA FRAMEWORK PHP 39 Introduzione n n n n n n n n Ruby e Python hanno un framework di riferimento per lo sviluppo di applicazioni web Lo stesso non si può dire per PHP. PHP nasce infatti come linguaggio per il web. Tra i frameworks più popolari: Zend Symfony CakePhP CodeIgniter (?) 40 © 2007 - CEFRIEL ZEND 41 Zend 2 n n n Zend Framework 2 è un framework open-source object-oriented si basa e sfrutta le caratteristiche di PHP 5.3 – namespaces • per evitare collisioni tra codice proprio e di terze parti • introdurre alias per migliorare la leggibilità – late static binding – closures n caratteristiche – – – – MVC rendering di form HTML5 validazione e filtri autenticazione e autorizzazione 42 © 2007 - CEFRIEL Moduli n n n Zend usa un sistema modulare per l’organizzazione dell’applicazione. Il modulo Application contiene i controllers a livello root. Struttura di un modulo (definisce i namespaces) /module /Album /config /src /Album /Controller /Form /Model /view /album /album 43 ModuleManager n n n ModuleManager ha il compito di caricare e configurare un modulo. Cerca il Module.php nella directory root del modulo (module/Album) All’interno del file cerca la classe con Album\Module – Album è il namespace e deve essere uguale al nome della cartella – Module il nome della classe 44 Module.php namespace Album; class Module { public function getAutoloaderConfig() // chiamata dal ModuleManager { return array( 'Zend\Loader\ClassMapAutoloader' => array( __DIR__ . '/autoload_classmap.php', // quali classi trovare ), 'Zend\Loader\StandardAutoloader' => array( // e dove 'namespaces' => array( __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__, ), ), ); } public function getConfig() //chiamata dal ModuleManager { //specifica dove sono I controller e gli script della view return include __DIR__ . '/config/module.config.php'; }} 45 Aggiungere il modulo all’applicazione n n Nel file di configurazione dell’applicazione specifichiamo quali moduli caricare. config/application/config.php return array( 'modules' => array( 'Application', 'Album', ), //…. ); // <-- Add this line 46 Routing n n n n n Zend utilizza il paradigma URL ->Page -> Controller -> action per la definizione del routing. Ogni pagina è associata ad una action Tante action sono raggruppate in controller Tanti controller sono raggruppati in moduli Pagina Controller Azione Home AlbumController index Nuovo album AlbumController add Modifica album AlbumController edit Rimuovi album AlbumController delete Adesso dobbiamo definire gli URL 47 Routing n n n n n Zend utilizza il paradigma URL ->Page -> Controller -> action per la definizione del routing. Ogni pagina è associata ad una action Tante action sono raggruppate in controller Tanti controller sono raggruppati in moduli URL Pagina Controller Azione /album Home AlbumController index /album/add Nuovo album AlbumController add /album/edit/2 Modifica album AlbumController edit album/delete/4 Rimuovi album AlbumController delete Adesso vediamo come si specifca il routing. 48 Routing n module.config.php di Album 'router' => array( 'routes' => array( 'album' => array( 'type' => 'segment', 'options' => array( 'route' => '/album[/][:action][/:id]', 'constraints' => array( 'action' => '[a-zA-Z][a-zA-Z0-9_-]*', 'id' => '[0-9]+', ), 'defaults' => array( 'controller' => 'Album\Controller\Album', 'action' => 'index', ), ), ), ), ), 49 Controller: Convenzioni n Il Controller è una classe di nome {NomeDelController} Controller – Es: AlbumController n n Deve iniziare con lettera maiuscola Il nome del file deve essere come quello della classe – Es: AlbumController.php n E deve risiedere nella cartella Controller del modulo – Es: module/Album/src/Album/Controller n n La classe controller deve avere un metodo pubblico per ogni action Il nome del metodo deve essere {nomeAction}Action – Es: indexAction 50 Controller namespace Album\Controller; use Zend\Mvc\Controller\AbstractActionController; use Zend\View\Model\ViewModel; class AlbumController extends AbstractActionController { public function indexAction() { } public function addAction() { } // … } 51 Model n n n 1. Zend non fornisce di default un componenente Zend\Model Molti componenti però possono essere integrati a secondo delle esigenze. Due Approcci: Un approccio è avere diverse classi che rappresentano le entità del modello. – Utilizzare un mapping tra gli oggetti e le entità nel DB. 2. Utilizzare un ORM esterno – – Doctrine Propel 52 Model n module/Album/src/Album/Model/Album.php namespace Album\Model; class Album { public $id; public $artist; public $title; // copia i dati da array ai campi della classe public function exchangeArray($data) { $this->id = (!empty($data['id'])) ? $data['id'] : null; $this->artist = (!empty($data['artist'])) ? $data['artist'] : null; $this->title = (!empty($data['title'])) ? $data['title'] : null; } } 53 Mapping del modello con il DB namespace Album\Model; use Zend\Db\TableGateway\TableGateway; class AlbumTable { protected $tableGateway; public function saveAlbum(Album $album) { $data = array( 'artist' => $album->artist, 'title' => $album->title, ); $id = (int) $album->id; if ($id == 0) { $this->tableGateway->insert($data); } else { if ($this->getAlbum($id)) { $this->tableGateway->update($data, array('id' => $id)); } else { throw new \Exception('Album id does not exist'); } } } 54 Aggiorniamo il controller n n Per visualizzare i dati nella view ritorniamo un ViewModel Questo viene automaticamente passato allo script della view // module/Album/src/Album/Controller/AlbumController.php: // ... public function indexAction() { return new ViewModel(array( 'albums' => $this->getAlbumTable()->fetchAll(), )); } // ... 55 View <table class="table"> n index.phtml <tr> <th>Title</th> <th>Artist</th> <th> </th> </tr> <?php foreach ($albums as $album) : ?> <tr> <td><?php echo $this->escapeHtml($album->title);?></td> <td><?php echo $this->escapeHtml($album->artist);?></td> <td> <a href="<?php echo $this->url('album', array('action'=>'edit', 'id' => $album->id));?>">Edit</a> <a href="<?php echo $this->url('album', array('action'=>'delete', 'id' => $album->id));?>">Delete</a> </td> </tr> <?php endforeach; ?> </table> 56 SYMFONY 57 Symfony n n Framework PHP largamente ispirato da altri Frameorks come Rails, Django e Spring A differenza di Zend usaun ORM – Propel – Doctrine n n Testing con PHPUnit (come Zend) Utilizzo – Delicious – DailyMotion – Yahoo! Bookmarks 58 © 2007 - CEFRIEL Front Controller e Routing n n n n Anche Symfony come Spring utilizza il front controller pattern per il dispatching delle richieste. E’ implementato in app_dev.php Symfony utilizza YML come linguaggio per definire il routing. app/config/routing.yml _welcome: path: / defaults: { _controller: AcmeDemoBundle:Welcome:index } _demo: resource: "@AcmeDemoBundle/Controller/DemoController.php" type: annotation prefix: /demo 59 Controllers n n n I Controller in Symfony prendono in ingresso richieste HTTP e ritornano HTTPResponse (come in Django) In PHP vengono utilizzate variabili globali e funzioni ($_GET o $header()) Symfony invece fornisce due oggetti Request e Response use Symfony\Component\HttpFoundation\Response; $name = $request->query->get('name'); return new Response('Hello '.$name, Response::HTTP_OK, array('ContentType' => 'text/plain')); 60 Controllers e render n n n Symfony seleziona il contoller sulla base del valore _controller definito in routing.yml Es: AcmeDemoBundle:Welcome:index dove Welcome è il nome del controller e index è l’action // src/Acme/DemoBundle/Controller/WelcomeController.php namespace Acme\DemoBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class WelcomeController extends Controller { public function indexAction() { return $this->render('AcmeDemoBundle:Welcome:index.html.twig'); } } 61 Rounting e annotazioni n n Il routing non solo può essere definito in YML Ma anche in XML, PHP o tramite annotazioni _demo: resource: "@AcmeDemoBundle/Controller/DemoController.php" type: annotation prefix: /demo class DemoController extends Controller { /** * @Route("/hello/{name}", name="_demo_hello") * @Template() */ public function helloAction($name) { return array('name' => $name); } 62 Template n n Il controller effettua il render di template Twig Twig è l’engine di deafult ma può essere utilizzato PHP. {% extends "AcmeDemoBundle::layout.html.twig" %} {% block title "Hello " ~ name %} {% block content %} <h1>Hello {{ name }}!</h1> {% endblock %} 63 Twig n File di testo che possono generare diversi tipi di contenuto – HTML,XML, CSV, LaTex,… n Due tipi di delimitatori (come ERB in Rails) – {{ … }} Stampa la variabile o il risultato di un’espressione – {% … %} non ritorna (utile per i controlli logici, cicli …) <ul id="navigation"> {% for item in navigation %} <li><a href="{{ item.href }}">{{ item.caption }}</a></li> {% endfor %} </ul> 64 Controller e formati n n n Lo stesso controller puà essere utilizzato per renderizzare divesi formati (XML e HTML) A secondo del formato specificato viene chiamato il template associato Esempio – XML -> hello.xml.twig – HTML -> hello.html.twig n n Il formato può essere specificato nell’annotazione. Route non ambigua tramite il placeholder {format} /** * @Route("/hello/{name}.{_format}", defaults={"_format"="html"}, requirements={"_format"="html|xml|json"}, name="_demo_hello") * @Template() */ public function helloAction($name) { /… 65 Generazione di URL n Redirect: redireziona l’utente ad un altro URL return $this->redirect($this->generateUrl('_demo_hello', array('name' => 'Lucas'))); n il metodo generateUrl prende in ingresso il nome della route e un array di parametri. $response = $this->forward('AcmeDemoBundle:Hello:fancy', array('name' => $name, 'color' => 'green')); n Forward: inoltra la richiesta ad un’altra action 66 Caching n E’ possibile configurare la caching per specifiche richieste. La cache può essere configurata dalle annotazioni. n Esempio: cache di un giorno n /** * @Route("/hello/{name}", name="_demo_hello") * @Template() * @Cache(maxage="86400") */ public function helloAction($name) { return array('name' => $name); } 67 JAVASCRIPT 68 Introduzione n n n n n JavaScript è un linguaggio molto diffuso per il front-end del web Linguaggio interpretato Object based A tipizzazione dinamica Estensibile con moltissime librerie 69 © 2007 - CEFRIEL <script> n con il tag script è possibile includere codice javascript direttamente nella pagina <script language="javascript”> <!-- Let old browsers ignore script function isPositiveNum(s) { return (parseInt(s) > 0) } // End of ignored area </script> n Il browser ignora gli script e interpreta il codice all’interno. 70 Variabili n Le variabili possono contener – tipi predefiniti / oggetti/funzioni n Tipi predefiniti – – – – – n number string boolean null undefined Tipizzazione dinamica – var answer = 42 – answer = “Grazie a tutti” n Tipizzazione debole – tipi di dato convertiti automaticamente – y = 42 + “is the answer” // ritorna “42 is the answer” 71 Scope n Variabili possono essere locali o globali – variabli dichiarate senza var sono sempre globali n Scope di variabili locali: – disponibili solo all’interno della funzione n Scope di variabili globali: – disponibili in tutto il codice nel documento n NB: Non esiste lo scope di blocco – variabli definite dentro un blocco sono visibili anche all’esterno if (true) { var x = 5; } console.log(x); 72 Funzioni function function_name([par0] … [parN]) { /*codice*/ } n parametri non inizializzati sono di valore “undefined” function sum (add1, add2){ return add1 + add2; } var first = sum(3,4); // 7 var second = sum(3); // NaN var third = sum(5,4,5); // 9 73 Oggetti n Javascript utilizza: – Array per gestire collezioni indicizzate (indice intero) – Oggetti per rappresentare collezioni (chiave,valore) <script type="text/javascript"> var a = { name : 'mario', surname : 'rossi', getName : function(){return this.name;} } document.write(a.getName() + '<br/>'); a.surname = 'bianchi'; document.write(a.surname); </script> 74 Oggetti n Oggetti possono anche avere costruttori per la definizione di valori function LineItem (id, name, qty, price) { this.productID = id; this.productName = name; this.qty = qty; this.unitPrice = price; this.total = price * qty; } cartLineItem = new Array(); cartLineItem[0] = new LineItem('ABC123', 'InkJet Colori', 1, 120); cartLineItem[1] = new LineItem('RTT237', 'InkJet B/N', 2, 14); cartLineItem[2] = new LineItem('LLJ947', 'LaserJet Colori', 2, 21); 75 Oggetti n Con prototype è possibile emulare il concetto di classe in OOP function Employee () { this.name = “”; this.dept = “general”; } function Manager () { this.reports =[]; } Manager.prototype = new Employee; 76 Eventi n n n n n n Documenti HTML possono generare eventi quando caricati nel browser. Eventi sono tipicamente associati/generati da elementi HTML Il codice di scripting client-side è scritto per definire comportamenti lanciato da eventi. Esempio Un comportamento associato al caricamento della pagina può essere definito da una funzione javascript associato all’evento onLoad dell’elemento Body. Altri tipi di eventi – unload – blur – focus 77 Event Handler element.addEventListener myButton.addEventListener(‘click’, function(){alert(‘ciao’);}, false); n attributo HTML <button onclick = “alert(“ciao”)”> n proprietà di un elemento DOM myButton.onclick = function(event){alert(‘ciao’)} n 78 Eventi esempio <script language="JavaScript"> function main() { document.getElementById('idp').innerText = "New page content."; } </script> <html> <head> <title>Page Title</title> </head> <body> <p onClick=“main();” id="idp">Default page content.</p> </body> </html> 79 ESERCIZI 80 AJAX 81 © 2007 - CEFRIEL Ajax n n n n n Gruppo di metodi per lo sviluppo di applicazioni client-side interattive. Prendono dati da un server in maniera asincrona In background senza interferire con la visualizzazione e il comportamento della pagina esistente. L’utente non deve più aspettare che la pagina sia caricata completamente ad ogni interazione. Precauzioni sulla performance: – scambiare solo i dati necessari. – Durante la fase di caricamento del documento inviare meno dati possibili n Casi d’uso – – – – Validazione realtime dell’input dell’utente autocompletamenro Caricamento dei dati on demand UI complesse 82 Architettura 83 Tecnologie n Funzioni Javascript – Invocata quando un evento è stato lanciato n DOM – Permette di avere accesso e aggiornare elementi HTML tramite javascript n CSS – Modifica a runtime tramite javascript n XMLHttpRequest – oggetto JavaScript che gestisce le interazioni con il server in maniera asincrona 84 Ajax: Scenario n n n n n L’utente interagisce con la pagina web che genera un evento (es click di un bottone) Una funzione Javascript cattura l’evento e crea un oggetto XMLHttpRequest Tramite quest’oggetto viene inviata una richiesta al server La risposta del server è raccolta da una funzione di callback che processa il risultato. Aggiorna il DOM della pagina e mostra il risultato. 85 Ajax: scenario 86 Best practices n Non usare Ajax per le funzionalità core – Javascript seppur mascherato è visibile dall’utente n Sempre permettere all’utente di capire visualmente cosa sta succedendo. – Monitor di attività (progress, spinner) n n Definire un timeout di connessione Dare sempre all’utente la possibilità di fare abort dell’attività 87 JQUERY 88 Introduzione n n n Jquery è un framework Javascript, cross-browser per applicazioni web. Si pone l’obiettivo di semplificare lo sviluppo lato client di pagine HTML. Tantissime operazioni con poche linee di codice. – Ottenere l’altezza di un elemento – Far scomparire un elemento con dissolvenza n n La gestione degli eventi è completamente standardizzata Offre funzioni per Ajax molto utili per l’invio di dati. 89 © 2007 - CEFRIEL Core n Il Core di Jquery fornisce: – Costruttori per l’utilizzo della libreria • ottenere elementi tramite selettori • ottenere elementi tramite parametro • creazione di nuovi elementi – metodi e proprietà per accedere agli elementi contenuti in oggetto jQuery • numero degli elementi • iterazione sugli elementi • conoscere il selettore utilizzato – metodi per creare liste e code – metodi per l’estensione del framework – animazioni 90 Selettori n n I selettori sono strumenti utilizzati per ottenere o puntare elementi HTML della pagina Utilizzano la stessa sintassi di CSS – in base all’id • #idvalue – in base alla classe • .classname – gerarchie • ancestor, sibling – in base ad attributi o contenuti • :hidden, [type =“text”] 91 Attributi n n n n jQuery fornisce una API compatibile con tutti i browser per l’accesso e modifica degli attributi attr() Attributi generici hasClass(), addClass(), removeClass() classi metodi per il contenuto – html() – text() – val() 92 Manipolazione e Navigazione del DOM n Navigazione – Metodi per risalire a elementi padre – nodi fogli – elementi successivi n Manipolazione – – – – aggiungere/rimuovere nuovi elementi alla pagina sostituire elementi circondare elementi con nuovo contenuto eliminare tutti gli elementi contenuti in un nodo 93 CSS, Eventi ed Effetti n Controllo dello stile degli elementi – Cambiare, rimuovere o aggiungere proprietà grafiche – Ottenere e sostituire proprietà difficili da manipolare (dimensioni, scroll…) n Eventi – Il framework riconosce oggetti di tipo event e modifica le proprietà rendendoli uniformi – Gestione e propagazione semplificata n Effetti – Servono a manipolare la visibilità di elementi – fading, sliding… 94 Ajax n 1. 2. Sono fornite tre tipologie di funzioni che semplificano la gestione delle chiamate asincrone. Caricare contenuti dinamicamente Esecuzione richieste 1. Metodo GET 2. Metodo POST 3. Interazione con javascript 1. Funzione per caricare un oggetto JSON 2. caricare un file javascript remoto ed eseguirlo 95 Oggetto jQuery n n L’oggetto principale, di nome jQuery è tipicamente utilizzato con l’alias $ Selettori – Ritorna tutte le immagini di classe a e/o b – $(“img.a, img.b”); n Concatenazione del codice $(“a”).css({color : “red”, width : “150px”}) .bind( "click", myFunctionPointer ).show( "1000" ); 96 Inizializzazione <!doctype html> <html> <head> <meta charset="utf-8" /> <title>Demo</title> </head> <body> <a href="http://jquery.com/">jQuery</a> <script src="jquery.js"></script> <script> // Your code goes here. </script> </body> </html> 97 document ready n n n Per permettere che il codice venga eseguito quando il browser finisce di caricare la pagina. Abbiamo visto la versione JavaScript onload Problemi: – Il codice non parte finché tutte le immagini sono state caricate – Inclusi i banner pubblicitari n jQuery $( document ).ready(function() { // Your code here. }); 98 Esempio $( document ).ready(function() { $( "a" ).click(function( event ) { alert( "Thanks for visiting!" ); }); }); cliccando su un link viene mostrato un popup e visualizzata la pagina linkata n possiamo prevenire l’azione di default $( document ).ready(function() { $( "a" ).click(function( event ) { event.preventDefault(); alert( ”Link no longer working!" ); }); }); n 99 Aggiungere e Rimuovere Classi HTML n n n n n Metodo addClass $(“a”).addClass(“test”) aggiunge la classe test a tutti gli elementi a (link) Metodo remove Class $(“a”).removeClass(“test”) 100 Effetti n n jQuery offre degli effetti e delle animazioni agli elementi Esempio: hide $( "a" ).click(function( event ) { event.preventDefault(); $( this ).hide( "slow" ); }); 101 CallBacks e Funzioni n n n n n JavaScript permette di passare funzioni come parametri da eseguire più in avanti nel tempo. La callback è una funzione passata come parametro ad un’altra funzione. E’ eseguita dopo che la funzione padre ha terminato. Nel frattempo il browser può eseguire altre funzioni e altro. Senza Argomenti $.get( "myhtmlpage.html", myCallBack ); n Con parametri $.get( "myhtmlpage.html", function() { myCallBack( param1, param2 ); }); 102 Ajax e JQuery n n n n Ci sono molti modi per utilizzare AJAX con jQuery. Uno dei più semplici per caricare dati asincronamente è il metodo load Selezione un elemento nel quale inserire i dati caricati ed esegui load. Prende in ingresso l’url della risorsa da caricare. 103 Esempio n Abbiamo il file content.html che contiene i dati da caricare <div id="divContent"> <b>This is external content</b> </div> And there's more of it n Lo carichiamo nell’elemento divTestArea1 <div id="divTestArea1"></div> <script type="text/javascript"> $(function() { $("#divTestArea1").load("content.html"); }); </script> 104 Load con selector n n E’ possibile specificare un selettore come parametro della load. In questo modo possiamo caricare solo parte del contenuto. <div id="divTestArea2"></div> <script type="text/javascript"> $(function() { $("#divTestArea2").load("content.html #divContent"); }); </script> 105 Load con callback <div id="divTestArea3"></div> <script type="text/javascript"> $(function() { $("#divTestArea3").load("no-content.html", function(responseText, statusText, xhr) { if(statusText == "success") alert("Successfully loaded the content!"); if(statusText == "error") alert("An error occurred: " + xhr.status + " - " + xhr.statusText); }); }); </script> 106 Metodi get() e post() n n I metodi get() e post() permettono di inviare facilmente richieste HTTP e riceve la risposta indietro. Metodo get() Versione con callback <script type="text/javascript"> $(function() { $.get("content.html", function(data, textStatus) { alert("Done, with the following status: " + textStatus + ". Here is the response: " + data); }); }); </script> 107 Metodi get() e post() n Metodo post() Versione con callback e parametri in ingresso. La callback viene chamata solo in caso di successo. <script type="text/javascript"> $(function() { $.post("test_post.php", { name: "John Doe", age: "42" }, function(data, textStatus) { alert("Response from server: " + data); }); }); </script> 108 Ajax $.ajax({ url: "http://fiddle.jshell.net/favicon.png", beforeSend: function( xhr ) { xhr.overrideMimeType( "text/plain; charset=x-userdefined" ); } }) .done(function( data ) { if ( console && console.log ) { console.log( "Sample of data:", data.slice( 0, 100 ) ); } }); 109 JQUERY UI 110 Introduzione n jQuery UI è un insieme che raccoglie diversi elementi per l’interfaccia grafica. – interazioni, effetti, widgets e temi. n jQuery UI Demos – http://jqueryui.com/demos/ n 1. Utilizzo importare il framework <link rel="stylesheet" href="css/themename/jquery-ui.custom.css" /> <script src="js/jquery.min.js"></script> <script src="js/jquery-ui.custom.min.js"></script> 2. 3. HTML : <input type="text" name="date" id="date" /> JavaScript : $( "#date" ).datepicker(); 111 © 2007 - CEFRIEL jQueryUI Opzioni $( "#mySliderDiv" ).slider({ orientation: "vertical", min: 0, max: 150, value: 50 }); 112 Progettazione del Tema n n n jQuery UI offre un tool chiamato ThemeRoller per la personalizzazione del tema dei widget. http://jqueryui.com/themeroller/ Theme Roller reindirizza a Download Center per definire il pacchetto personalizzato da scaricare (quali widget si ha intenzione di utilizzare) con il nuovo tema definito. 113 NODE.JS 114 Introduzione n n n Node.js è un framework per realizzare applicazioni Web in JavaScript. Con Node.js possiamo sviluppare in javascript lato server La piattaforma è basata sul Javascript Engine V8 (di Google) – utilizzato anche da Chrome n Caratteristica principale: Approccio asincrono – Le risorse del sistema sono acceduta con un approccio eventdriven. – E non il classico modello dei web server basato su processi. 115 © 2007 - CEFRIEL Paradigma Event-driven n n n n n n Si lancia un’azione quando accade qualcosa. Ogni azione risulta asincrona e non sequenziale come nei classici web server. Basato da un sistema di callback gestito dal runtime. Vantaggi:Efficienza Il comportamento asincrono permette all’applicazione può fare altro. Questa caratteristica cambia anche l’approccio allo sviluppo. 116 Esempio /** approccio sincrono (classico) **/ var dato = ottieniDatoDaRemoto(url); alert(dato); /** approccio ad eventi (asincrono) **/ ottieniDatoDaRemoto(url, function(dato) { alert(dato); }); //la funzione ritorna subito 117 Creazione di un web server var http = require('http'); var server = http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello Worldn'); }) server.listen(1337, '127.0.0.1'); console.log('Server running at http://127.0.0.1:1337/'); 118 NPM n Il registro NPM è il repositori di librerie scritto per node.js n Equivalente a gem in Rails e PEAR in PHP n NPM supporta anche la gestione dell’installazione e delle versioni. 119 Moduli n Globals include una serie di API nel namespace globale richiamabili direttamente in tutta l’applicazione. – require permette di include moduli aggiuntivi – setTimeout e setInterval per i timer – include oggetti fondamentali come consolo che permette di accedere allo std input e std error n http – include una serie di oggetti per utilizzare il protocollo e avviare il server n url – definizione dell’url e suo parsing in un oggetto n path – accesso a percorsi reali della macchina (navigazione cartelle) n … 120 Utilizzare i moduli nelle app n si utilizza la funzione globale require var url = require('url'); console.log(url.parse('http://www.google.com')); console.log(url.format({ host: ’www.google.com', protocol: 'http' })); n require: – cerca nella cartella di default node_modules – è possibile includere tutto un insieme di moduli raccolto in una cartella 121 Creazione Modulo n n Un modulo è uno o più file contenenti funzioni js Ogni funzione viene esportata tramite l’oggetto exports //simplemath.js var sum = function(a, b) { //definiamo la funzione sum return a+b; } var product = function(a, b) { //definiamo la funzione product return a*b; } var private = function(a,b) { return "Io sono private!!"; } exports.sum = sum; //esportiamo la funzione sum exports.product = product; //esportiamo la funzione product 122 Utilizzo del modulo //app.js var sm = require('./simplemath'); console.log(sm.sum(1,2)); //echo 3 console.log(sm.product(1,2)); //echo 2; console.log(sm.private(1,2)); //error! 123 Dispatcher n Il Dispatcher permette di associare richieste diverse a funzioni diverse. var dispatcher = require('httpdispatcher'); dispatcher.onGet("/page1", function(req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Page One'); }); dispatcher.onPost("/page2", function(req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Page Two'); }); http.createServer(function (req, res) { dispatcher.dispatch(req, res); }).listen(1337, '127.0.0.1'); 124 HttpDispatcher var HttpDispatcher = function() { this.listeners = { get: [ ], post: [ ] }; } HttpDispatcher.prototype.on = function(method, url, cb) { this.listeners[method].push({ cb: cb, url: url }); } HttpDispatcher.prototype.onGet = function(url, cb) { this.on('get', url, cb); } HttpDispatcher.prototype.onPost = function(url, cb) { this.on('post', url, cb); } 125 HttpDispatcher n Metodo dispatch e esportazione HttpDispatcher.prototype.dispatch = function(req, res) { var parsedUrl = require('url').parse(req.url, true); var method = req.method.toLowerCase(); this.listener[method][parsedUrl.pathname](req, res); } module.exports = new HttpDispatcher(); 126 Template System con Bind dispatcher.onGet('/home', function(req, res, chain) { bind.toFile('tpl/home.tpl', { name: 'Alberto', address: 'via Roma', city: 'Milano' }, function(data) { res.writeHead(200, {'Content-Type': 'text/html'}); res.end(data); }); }); /* file tpl/home.tpl */ <h1>(:name ~ Marco:)</h1> <b>(:address:) - (:city:)</b> 127