-
Notifications
You must be signed in to change notification settings - Fork 3
Home
Il Target di questo progetto è quello di realizzare un applicativo web in grado di offrire un servizio di evacuazione efficiente, efficace e facilmente fruibile attraverso il world wide web. Per fare ciò ci siamo avvalsi di alcune tecnologie quali:
- HTML 5
- PHP 5
- Zend framework
- Javascript
- JQuery
- Materialize
- MySql
Il primo step della realizzazione dell’applicativo web è stata l’analisi degli elementi appartenenti al dominio applicativo in sviluppo quali:
- Gli utenti - opportunamente categorizzati
- Gli edifici - suddivisi in piani e zone
- Gli eventi - suddivisi in base alla tipologia
I Piani di Fuga - inerenti ad un determinato piano Per esigenze tecniche sono stati aggiunte successivamente le Faq consultabili da un utente e le Posizioni rappresentanti la collocazione di un utente all’interno di un edificio. Quello che abbiamo ottenuto è il seguente schema Entity Relationship
In seguito è stato tradotto in uno schema logico che rappresenta un buon compromesso tra ottimizzazione e fruibilità delle informazioni, dosando la normalizzazione e l’eliminazione delle ridondanze in funzione di un agevole manipolazione in Zend Framework
Il motivo per cui si adotta un design pattern è quello di rendere i progetti di tipo object-oriented più flessibili e riutilizzabili. Nello specifico l’MVC si articola in tre spazi di lavoro principali:
- Il Model con il compito di interfacciarsi con il DMBS che fornisce i servizi MySQL e custodisce le informazioni in una base di dati.
- La View che ha il compito di servire l’utenza delle informazioni ad essa referenziate rendendo tale meccanismo il più user-friendly possibile
- Il Controller , cuore dell’applicativo, che orchestra model e view filtrando le interazioni tra i due.
Zend è un framework opensource php che negli anni ha riscosso un discreto successo e vanta una grande community che la supporta. Avvalendosi del design patern mvc è uno strumento di sviluppo molto versatile che permette di realizzare applicativi web scalabili ed affidabili. Nel progetto qui realizzato ci si avvale della versione 1.12.13 . Passiamo ora ad una più attenta analisi dei componenti del progetto
File di configurazione del bootstrap contenente
- il settaggio del base url
- l’inizializzazione dei placeholders delle view
- il settaggio del loader con la definizione del namespace App_ e l’aggiunta delle risorse 'modelResource','models/resources' e 'Resource’ indispesabili per il naming delle nostre classi.
- la definizione dell’ adapter che include il file include/connect.php con le credenziali di login.
il Model è strutturato su tre directory
- le classi Model sono quell’insieme di classi che permettono ad un alto livello di astrazione di comunicare con la base di dati e di ottenere degli oggetti facilmente consultabili
- le classi Resources rappresentano ciascuna una specifica tabella dalle quali possono prelevare un set di elementi da trasmettere ad una determinata classe Model
- le classi Items che rappresentano una singola occorrenza di una tabella e permettono di accedervi e manipolarla per poi comunicarla alla corrispettiva classe Model
[Class diagram del model]()
Alcune implementazioni degne di nota sono sicuramente quelle che implementano dei Join su delle tabelle con chiavi esterne
//metodo che restituisce i piani di fuga di una zona
public function getAssegnazioniByZona($zona){
$select=$this->select()
->where('zona= ? ',$zona)
->where('abilitato=1');
return $this->fetchAll($select);
}
//metodo che restituisce tutte le persone all’interno di un determinato edifici
public function getNumCollocazioniByEdificio($edificio) {
$select = $this->select()
->setIntegrityCheck(false)
->from(array('c' => 'collocazione'), array())
->join (array('pos' => 'posizione'), 'c.idPosizione=pos.id', array())
->join (array('p' => 'piano'), 'pos.numPiano=p.numeroPiano AND p.edificio=pos.edificio',
array('numPersone' => 'COUNT(*)'))
->where ('p.edificio = ?', $edificio);
return $select;
}
La view dell’applicativo contiene un file .phtml per ogni azione del controller da cui è referenziata.
##Controller Il controller è la struttura che orchestra view e model ed è composto da quattro classi rappresentati ognuna una tipologia diversa di utente che accede all’applicativo ed un errorController che reindirizza agli errori.
Il Controller fa largo uso dei metodi php file_exist()
unlink()
e rename()
per manipolare le immagini e le piante degli edifici che sono collocati e strutturati
secondo una gerarchia ad albero nella cartella /image della sezione public di Zend.
Qui di seguito riproponiamo (in uno dei metodi più importanti del controller livello3 che ha il compito di rinominare tutti i file collegati ad un edificio e di aggiornare il database)
/**
* Rinomino tutti i file e le occorrenze del db collegate ad un deerminato edificio
* @param $nome_vecchio_edificio
* @param $nome_nuovo_edificio
*/
protected function rinominaEdificio($nome_vecchio_edificio,$nome_nuovo_edificio){
//model
$edificioModel = new Application_Model_Edifici();
$posizioniModel = new Application_Model_Posizioni();
$pianiModel = new Application_Model_Piani();
$pdfModel = new Application_Model_PianoDiFuga();
$adminModel = new Application_Model_Admin();
$stringa_esplosa = null;
//edificio
$set = $edificioModel->getEdificio($nome_nuovo_edificio); //attenzione [0]
$mappa_vecchio_edificio = $set[0]->mappa;
$stringa_esplosa = explode(".", $mappa_vecchio_edificio);
//rinomino il file corrispondente
$file1 = APPLICATION_PATH . '/../public/image/edifici/' . $mappa_vecchio_edificio;
$nuovoNomeFile = $nome_nuovo_edificio . "." . end($stringa_esplosa);
$file2 = APPLICATION_PATH . '/../public/image/edifici/' . $nuovoNomeFile;
rename($file1, $file2);
$edificioModel->updateEdificio(array('mappa' => $nuovoNomeFile), $nome_nuovo_edificio);
//aggiorno le posizioni nel db
$posizioniModel->updateByEdificio($nome_vecchio_edificio,array(
'edificio' => $nome_nuovo_edificio
));
//aggiorno la zona nel db
$adminModel->updateZoneByEdificio($nome_vecchio_edificio,array(
"edificio" => $nome_nuovo_edificio
));
//pianta
$pianiset = $pianiModel->getPianiByEdificio($nome_nuovo_edificio);
foreach ($pianiset as $item){
//prelevo la pianta vecchia
$vecchiaPianta = $item->pianta;
$pianta_esplosa = explode("Piano",$vecchiaPianta);
$nuovaPianta = $nome_nuovo_edificio . " Piano".end($pianta_esplosa);
//aggiorno nel db
$pianiModel->updatePianiByPianta($vecchiaPianta,array(
"pianta" => $nuovaPianta
));
//rinomino il file
$file1 = APPLICATION_PATH . '/../public/image/piante/' . $vecchiaPianta;
$file2 = APPLICATION_PATH . '/../public/image/piante/' . $nuovaPianta;
rename($file1, $file2);
//mappature
$file_vecchia_mappa = $nome_vecchio_edificio . " Piano " .$item->numeroPiano . ".txt";
$file_nuova_mappa = $nome_nuovo_edificio . " Piano " . $item->numeroPiano . ".txt";
$path1 = APPLICATION_PATH . '/../public/image/piante/map/' . $file_vecchia_mappa;
$path2 = APPLICATION_PATH . '/../public/image/piante/map/' . $file_nuova_mappa;
if(file_exists($path1)){
rename($path1,$path2);
}
//piani di fuga
print_r($item->numeroPiano.'<br>');
$setpdf = $pdfModel->getByEdificioPiano($nome_vecchio_edificio,$item->numeroPiano);
//per ogni piano di fuga colledato ad un determinato piano
foreach ($setpdf as $pdf){
//modifico l'occorenza nel db
$vecchiaPiantaPdf = $pdf->pianta;
$vecchiaPiantaEsplosa = explode("Piano",$vecchiaPiantaPdf);
$nuovaPiantaPdf = $nome_nuovo_edificio . " Piano" .end($vecchiaPiantaEsplosa);
$pdfModel->updateByPianta($vecchiaPiantaPdf,array(
'pianta' => $nuovaPiantaPdf
));
//aggiorno il file
$path1 = APPLICATION_PATH . '/../public/image/piante/piani di fuga/' . $vecchiaPiantaPdf;
$path2 = APPLICATION_PATH . '/../public/image/piante/piani di fuga/' . $nuovaPiantaPdf;
if(file_exists($path1)){
rename($path1,$path2);
}
}
//zone
$file_vecchia_zona_jpg = $nome_vecchio_edificio . " Piano " . $item->numeroPiano . ".jpg";
$file_vecchia_zona_png = $nome_vecchio_edificio . " Piano " . $item->numeroPiano . ".png";
$file_nuova_zona_jpg = $nome_nuovo_edificio. " Piano " . $item->numeroPiano . ".jpg";
$file_nuova_zona_png = $nome_nuovo_edificio . " Piano " . $item->numeroPiano . ".png";
$path_old_jpg = APPLICATION_PATH . '/../public/image/piante/zone/' . $file_vecchia_zona_jpg;
$path_old_png = APPLICATION_PATH . '/../public/image/piante/zone/' . $file_vecchia_zona_png;
$path_new_jpg = APPLICATION_PATH . '/../public/image/piante/zone/' . $file_nuova_zona_jpg;
$path_new_png = APPLICATION_PATH . '/../public/image/piante/zone/' . $file_nuova_zona_png;
//controllo se ho un file in jpg
if(file_exists($path_old_jpg)){
//aggiorno in jpg
rename($path_old_jpg,$path_new_jpg);
}
//controllo se ho un file in png
if(file_exists($path_old_png)){
//aggiorno in png
rename($path_old_png,$path_new_png);
}
}
}
Zend Framework, fra i vari vantaggi, offre un interfaccia prestabilita per creare delle classi Form da inserire nell’applicativo . Nel nostro caso sono state inserite per una moltitudine di operazioni quali:
- registrazione e log-in
- modifica dei dati di un utente
- posizionamento
- modifica ed inserimento delle informazioni di un edificio Inoltre è stato realizzato un Custom Validator
/**
* Questo metodo prende in input una stringa che rappresenta le zone da
* inserire usufruendo di un’espressione regolare verifica se la stringa
* è formattata in modo corretto.
*/
class App_Validate_ValidatoreZona extends Zend_Validate_Abstract
{
const errore=null;
protected $_messageTemplates = array(
self::errore => "Le zone devono essere del tipo [A-Z], separate da uno spazio, non ripetute e lunghe massimo un carattere"
);
public function isValid($value)
{
$this->_setValue($value);
$controllo=str_replace(" ", "", $value);
$nespressioneregolare=strlen($controllo)-1;
$n=strlen($controllo)-1;
for($cont=0;$cont<$n+1;$cont++){
$arrayappoggio=array();
$varappoggio=$controllo[$cont];
for($cont2=$cont;$cont2<$nespressioneregolare;$cont2++)
{
$arrayappoggio[$cont2]=$controllo[$cont2+1];
}
if(in_array($varappoggio, $arrayappoggio))
{
$this->_error(self::errore);
return false;
}
$n--;
}
if (!mb_ereg_match('([A-Z][[:space:]]){'.$nespressioneregolare.'}[A-Z]',$value)) {
$this->_error(self::errore);
return false;
}
return true;
}
}
class Application_Form_Inseriscizone extends Zend_Form
{
public function init()
{
$this->setMethod('post');
$this->setName('inseriscizone');
$this->setAttrib('enctype', 'multipart/form-data');
$this->setAction(''); // definirò l'azione nel controller quando istanzio la form
$myValidator = new App_Validate_ValidatoreZona();
$this->addElement('text','zone', array(
'required' => true,
'label' => 'Zone (inserisci le zone separate da uno spazio)',
'validators'=>array($myValidator)
));
$this->addElement('file', 'pianta', array(
'label' => 'Pianta',
'destination' => APPLICATION_PATH.'/../public/image/piante/zone',
'validators' => array(
array('Count', false, 1),
array('Size', false, 30960000),
array('Extension', false, array('jpg','png'))
),
'required' => true
));
$this->addElement('submit', 'ok', array(
'class' => 'btn waves-yellow green',
));
}
}
Queste due tecnologie che fanno uso del linguaggio javascript sono l’ultima avanguardia della programmazione lato client. La prima permette di rendere meno verbosa la scrittura degli script, eseguire validazione lato client e di “pilotare” le animazioni delle interfacce utente. La seconda permette di ovviare al regolare workflow del modello Client-Server realizzando una **interazione asincrona **.
Il sito si serve di alcune animazioni jQuery nell’indexView del Livello1Controller per segnalare all’utente un pericolo imminente. Lo script esegue il Polling per ricaricare periodicamente la pagina e qualora sia in atto una procedura di evacuazione viene suggerito all’utente di consultare il piano di fuga per la sua posizione
<script>
//polling
$( document ).ready(function() {
setInterval(poll, 45000);
function poll() {
location.reload();
}
});
//animazione che fa lampeggiare lo sfondo della pagina
if($evacuare){
$( document ).ready(function() {
setInterval(alertFunc, 800);
function alertFunc() {
$( "body" ).effect("highlight",{color: 'yellow'},600);
}
});
}
</script>
L’interazione asincrona con Ajax è presente sulla DashboardView del Livello2Controller per animare le Form delle evacuazioni
$("#edificio").on("change", function(){
var actionUrl= ajaxEdificio();
$.ajax({
type : 'POST',
url : actionUrl,
data : $("#edificio").serialize(),
dataType : 'json',
success : pianiPopulate
});
});
function pianiPopulate(data){
$('dd#piano-element').find("ul").find("li").remove();
$('dd#piano-element').find("select").find("option").remove();
$.each(data, function(key, val){
$('dd#piano-element').find("ul."+"dropdown-content select-dropdown").append('<li><span>Piano'+ val +'</span></li>');
$('dd#piano-element').find("select").append('<option value="'+ val +'">Piano '+ val +'</option>');
});
$('select').material_select();
}
Uno dei requisiti principali di un applicazione web al passo con i tempi è la fruibilità dei contenuti.
Per venire in contro a tale esigenza abiamo adottato un Framework CSS molto versatile che adotta i canoni del Material Design rendendo la pagina conforme allo standard a cui si riferiscono tutti i principali servizi che adoperano nel Worl Wide Web.
Questo framework, utilizzando le librerie JQuery, predispone dei fogli di stile predefiniti che reinterpretano i tag html e, qualora inseriti come attributo, adottano gli stili delle classi definite per assegnare determinate animazioni ad un componente
una form normale realizzata con zend form
una form realizzata con Materialize
#Schema di link