NF1 - Model Vista Controlador (10h)

De wikiserver
Dreceres ràpides: navegació, cerca

MVC

Introducció

El patró d'arquitectura MVC (Model Vista Controlador) és un patró de desenvolupament de software que defineix l'organització independent del Model (Objectes de Negoci), la Vista (interfície amb l'usuari o un altre sistema) i el Controlador (controlador del workflow de l'aplicació).

L'arquitectura MVC separa la lògica de negoci (el model) i la presentació (la vista) pel que s'aconsegueix un manteniment més senzill de les aplicacions. Si per exemple una mateixa aplicació ha d'executar-se tant en un navegador estàndard com un un navegador d'un dispositiu mòbil, solament és necessari crear una vista nova per a cada dispositiu; mantenint el controlador i el model original. El controlador s'encarrega d'aïllar al model i a la vista dels detalls del protocol utilitzat per a les peticions (HTTP, consola de comandos, email, etc.). El model s'encarrega de l'abstracció de la lògica relacionada amb les dades, fent que la vista i les accions siguin independents de, per exemple, el tipus de gestor de bases de dades utilitzat per l'aplicació.

D'aquesta forma, dividim el sistema en tres capes on, com explicarem més endavant, tenim l'encapsulació de les dades, la interfície o vista per un altre i finalment la lògica interna o controlador.

  • El Model representa la informació amb la qual treballa l'aplicació, és a dir, la seva lògica de negoci.
  • La Vista transforma el model en una pàgina web que permet a l'usuari interactuar amb ella.
  • El Controlador s'encarrega de processar les interaccions de l'usuari i realitza els canvis apropiats en el model o en la vista.

Per entendre com funciona el nostre patró Model - vista - controlador, s'ha d'entendre la divisió a través del conjunt d'aquests tres elements i com aquests components es comuniquen uns amb els altres i amb altres vistes i controladors externs al model principal. Per a això, és important saber que el controlador interpreta les entrades de l'usuari (tant teclat com el ratolí), enviat el missatge d'acció al model i a la vista perquè es procedeixi amb els canvis que es considerin adequats.

El model

El model representa la part de l'aplicació que implementa la lògica de negoci. Aixó significa que és responsable de la recuperació de dades convertint-los en conceptes significatius per a l'aplicació, així com el seu processament, validació, associació i qualsevol altra tasca relativa a la manipulació d'aquestes dades.

A primera vista els objectes del model poden ser considerats com la primera capa de la interacció amb qualsevol base de dades que podria estar utilitzant la teva aplicació. Però en general representen els principals conceptes entorn dels quals es desitja implementar un programa.

En el cas d'una xarxa social, la capa de model es faria càrrec de tasques tals com guardar dades de l'usuari, l'emmagatzemament d'associacions amb amics, l'emmagatzematge i la recuperació de fotos dels usuaris, trobar suggeriments de nous amics, etc. Mentre que els objectes del model poden ser considerats com a “Amic”, “Usuari”, “Comentari” i “Foto”.

El model és el responsable de:

  • Accedir a la capa d'emmagatzematge de dades. L'ideal és que el model sigui independent del sistema d'emmagatzematge.
  • Defineix les regles de negoci (la funcionalitat del sistema). Un exemple de regla pot ser: "Si la mercaderia demanada no està en el magatzem, consultar el temps de lliurament estàndard del proveïdor".
  • Notificarà a les vistes, si cal, els canvis que en les dades pugui produir un agent extern (per exemple, un fitxer per lots que actualitza les dades, un temporitzador que desencadena una inserció, etc.).

El controlador

La capa del controlador gestiona les peticions dels usuaris. És responsable de respondre la informació sol·licitada amb l'ajuda tant del model com de la vista.

Els controladors poden ser vists com a administradors cuidant que tots els recursos necessaris per completar una tasca es deleguin als treballadors més adequats. Espera peticions dels clients, comprova la seva validesa d'acord a les normes d'autenticació o autorització, delega la cerca de dades al model i selecciona el tipus de resposta més adequat segons les preferències del client. Finalment delega aquest procés de presentació a la capa de la Vista.

El controlador és responsable de:

  • Rebre els esdeveniments d'entrada (un clic, un canvi en un camp de text, etc.).
  • Conté regles de gestió d'esdeveniments, del tipus "SI Esdeveniment Z, llavors Acció W". Aquestes accions poden suposar peticions al model o a les vistes. Una d'aquestes peticions a les vistes pot ser una trucada al mètode "Actualitzar()". Una petició al model pot ser "Obtenir_temps_de_lliurament ( nova_ordre_de_venda )".

La vista

La vista fa una presentació de les dades del model separada dels objectes del model. És responsable de l'ús de la informació de la qual disposa per produir qualsevol interfície de presentació de qualsevol petició que es present.

Per exemple, com la capa de model retorna un conjunt de dades, la vista els usaria per fer una pàgina HTML que els contingui. O un resultat amb format XML perquè altres aplicacions puguin consumir.

La capa de la Vista no es limita únicament a HTML o text que representi les dades, sinó que pot ser utilitzada per oferir una àmplia varietat de formats en funció de les seves necessitats tals com videos, música, documents i qualsevol altre format que puguis imaginar.

Les vistes són responsables de:

  • Rebre dades del model i els mostra a l'usuari.
  • Tenen un registre del seu controlador associat (normalment perquè a més ho instància).
  • Poden donar el servei de "Actualització()", perquè sigui invocat pel controlador o pel model (quan és un model actiu que informa dels canvis en les dades produïdes per altres agents).

Funcionament gràfic del patró MVC

Funcionamiento-mvc.png

Per què utilitzar MVC?

  • És un patró de disseny de programari veritablement provat que converteix una aplicació en un paquet modular fàcil de mantenir i millora la rapidesa del desenvolupament.
  • La separació de les tasques de la teva aplicació en models, vistes i controladors fa que la seva aplicació sigui a més molt lleugeres d'entendre.
  • Les noves característiques s'afegeixen fàcilment i agregar coses noves a codi vell es fa molt senzill. El disseny modular també permet als desenvolupadors i els dissenyadors treballar simultàniament, incloent la capacitat de fer prototips ràpids.
  • La separació també permet als desenvolupadors fer canvis en una part del la aplicació sense afectar als altres.

Classes i objectes PHP

Una classe és una plantilla (motlle), que defineix atributs (el que coneixem com a variables) i mètodes (el que coneixem com a funcions). La classe defineix els atributs i mètodes comuns als objectes d'aquest tipus, però després, cada objecte tindrà els seus propis valors i compartiran les mateixes funcions.

Hem de crear una classe abans de poder crear objectes (instàncies) d'aquesta classe. En crear un objecte d'una classe, es diu que es crea una instància de la classe o un objecte pròpiament dit.

Exemple de definició d'una classe:

<html>
<head>
<title>Pruebas</title>
</head>
<body>
<?php
class Persona {
  private $nombre;

  public function __construct() 
  {
   $this->nombre="";
  }
  public function inicializar($nom)
  {
    $this->nombre=$nom;
  }
  public function imprimir()
  {
    echo $this->nombre;
    echo '<br>';
  }
}

$per1=new Persona();
$per1->inicializar('Juan');
$per1->imprimir();
$per2=new Persona();
$per2->inicializar('Ana');
$per2->imprimir();
?>
</body>
</html>

La sintaxi básica para declarar la clase es:

class [Nombre de la Clase] {
  [atributos]
  [métodos]
}

Els atributs normalment són privats (private), ja veurem que això significa que no podem accedir al mateix des de fora de la classe. Després per definir els mètodes s'utilitza la mateixa sintaxi que les funcions del llenguatge *PHP. Dèiem que una classe és un motlle que ens permet definir objectes. Ara vegem com és la sintaxi per a la definició d'objectes de la classe Persona:

$per1=new Persona();
$per1->inicializar('Juan');
$per1->imprimir();

Definim un objecte anomenat $per1 i ho vam crear assignant-li el que retorna l'operador new. Sempre que volem crear un objecte d'una classe utilitzem la sintaxi new [Nom de la Classe].

Després per cridar als mètodes hem d'antecedir el nom de l'objecte l'operador -> i finalment el nom del mètode. Per poder cridar al mètode,aquest ha de ser definit públic (amb la paraula clau public). En el cas que tingui paràmetres li els enviem:

$per1->inicializar('Juan');

L'últim a tenir en compte quant a la sintaxi d'aquest primer problema és que quan accedim als atributs dins dels mètodes hem d'utilitzar els operadors $this-> (this i ->):

public function inicializar($nom)
  {
    $this->nombre=$nom;
  }

L'atribut $nombre solament pot ser accedit pels mètodes de la classe Persona.

Propietats d'una classe

Les propietats representen certes característiques de l'objecte en si mateix. Es defineixen anteposant la paraula clau var al nom de la variable (propietat). Les propietats poden gaudir de diferents característiques, com per exemple, la visibilitat: poden ser públiques, privades o protegides. Com veurem més endavant, la visiblidad de les propietats, és aplicable també a la visibilitat dels mètodes.

Propietats públiques Les propietats públiques es defineixen anteposant la paraula clau public al nom de la variable. Aquestes, poden ser accedides des de qualsevol part de l'aplicació, sense restricció.

class Persona {
public $nom;
public $genero;
}

Propietats privades Les propietats privades es defineixen anteposant la paraula clau private al nom de la variable. Aquestes solament poden ser accedides per la classe que les va definir.

class Persona {
public $nom;
public $genero;
private $edat;
}

Propietats protegides Les propietats protegides poden ser accedides per la pròpia classe que la va definir, així com per les classes que l'hereten, però no, des d'altres parts de l'aplicació. Aquestes, es defineixen anteposant la paraula clau protected al nom de la variable:

class Persona {
public $nom;
public $genero;
private $edat;
protected $passaport;
}

Propietats estàtiques Les propietats estàtiques representen una característica de “variabilitat” de les seves dades, de gran importància en PHP 5. Una propietat declarada com a estàtica, pot ser accedida sense necessitat de instanciar un objecte. i el seu valor és estàtic (és a dir, no pot variar ni ser modificat). Aquesta, es defineix anteposant la paraula clau static al nom de la variable:

class PersonaAPositivo extends Persona {
public static $tipus_sagni = 'A+';
}

Accedint a les propietat d'un objecte

S'accedeix a una propietat no estàtica dins de la classe, utilitzant la pseudo-variable $this sent aquesta pseudo-variable una referència a l'objecte mateix:

return $this->nombre;

Quan la variable és estàtica, s'accedeix a ella mitjançant l'operador de resolució d'àmbit, doble dos-punts :: anteposant la paraula clau self o parent segons si tracta d'una variable de la mateixa classe o d'una altra de la qual s'ha heretat, respectivament:

print self::$variable_estatica_de_aquesta_classe;
print parent::$variable_estatica_de_classe_mare;

Accés a variables des de l'exterior de la classe S'accedeix a una propietat no estàtica amb la següent sintáxis: $objecte->variable Noti's a més, que aquest accés dependrà de la visibilitat de la variable. Per tant, solament variables públiques poden ser accedides des de qualsevol àmbit fora de la classe o classes heretades.

# creo l'objecte instanciando la classe
$persona_a_positiu = new PersonaAPositivo();
# accedeixo a la variable NO estàtica
print $persona_a_positiu->nom;

Per accedir a una propietat pública i estàtica l'objecte no necessita ser instanciado, permetent així, l'accés a aquesta variable mitjançant la següent sintáxis:

Classe::$variable_estàtica
# accedeixo a la variable estàtica
print PersonaAPositivo::$tipus_sagni;

Constants de classe Un altre tipus de propietat d'una classe, són les constants, aquelles que mantenen el seu valor de forma permanent i sense canvis. A diferència de les propietats estàtiques, les constants solament poden tenir una visibilitat pública. Pot declarar-se una constant de classe com qualsevol constant normal en PHP 5. L'accés a constants és exactament igual que al d'altres propietats.

const EL MEU_CONSTANT = 'Est és el valor estàtic del meu constant';

Mètodes d'una classe

El mètode d'una classe, és un algorisme igual al d'una funció. L'única diferència entre mètode i funció, és que cridem mètode a les funcions d'una classe (en la POO), mentre que cridem funcions, als algorismes de la programació estructurada. La forma de declarar un mètode és anteposant la paraula clau function al nom del mètode, seguit per un parell parèntesi d'obertura i tancament i claus que tanquin l'algorisme:

class Persona {
	#propietats
	#mètodes
	function donar_sang() {
		#...
	}
}

Igual que qualsevol altra funció en PHP, els mètodes rebran els paràmetres necessaris indicant aquells requerits, dins dels paréntisis

class Persona {
	#propietats
	#mètodes
	function donar_sang($destinatari) {
		#...
	}
}

Mètodes públics, privats, protegits i estàtics

Els mètodes, igual que les propietats, poden ser públics, privats, protegits o estàtics. La forma de declarar la seva visibilitat tant com les característiques d'aquesta, és exactament la mateixa que per a les propietats.

static function a() { }
protected function b() { }
private function c() { }

Mètodes abstractes A diferència de les propietats, els mètodes, poden ser abstractes com succeeix amb les classes. Per entendre millor els mètodes abstractes, podríem dir que a grans trets, els mètodes abstractes són aquells que es declaren inicialment en una classe abstracta, sense especificar l'algorisme que implementaran, és a dir, que solament són declarats però no contenen un “codi” que específique què faran i com ho faran.

abstract public function getValor();


Mètodes màgics

Aquests mètodes, atorguen una funcionalitat pre-definida per PHP, que poden aportar valor a les nostres classes i estalviar-nos grans quantitats de codi. El que molts programadors considerem, ajuda a convertir a PHP en un llenguatge orientat a objectes, cada vegada més robust. Entre els mètodes màgics, podem trobar els següents:

El Mètode Màgic __construct()

El mètode __construct() és aquell que serà invocat de manera automàtica, al instanciar un objecte. La seva funció és la d'executar qualsevol inicialització que l'objecte necessiti abans de ser utilitzat.

class Producte {
	#defineixo algunes propietats
	public $nom;
	public $preu;
	protected $estat;
	#defineixo el mètode set_estat_producte()
	protected function set_estat_producte($estat) {
		$this->estat = $estat;
	}
	# constructor de la classe
	function __construct() {
		$this->set_estat_producte('en ús');
	}
}

El mètode màgic __destruct()

El mètode __destruct() és l'encarregat d'alliberar de la memòria, a l'objecte quan ja no és referenciat. Es pot aprofitar aquest mètode, per realitzar altres tasques que es POO i MVC en PHP estimin necessàries al moment de destruir un objecte.

class Producte {
	#defineixo algunes propietats
	public $nom;
	public $preu;
	protected $estat;
	#defineixo el mètode set_estat_producte()
	protected function set_estat_producte($estat) {
		$this->estat = $estat;
	}
	# constructor de la classe
	function __construct() {
		$this->set_estat_producte('en ús');
	}
	# destructor de la classe
	function __destruct() {
		$this->set_estat_producte('alliberat');
	print 'L'objecte ha estat destruït';
	}
}

Altres mètodes màgics

PHP ens ofereix altres mètodes màgics tals com:

__get, __set, __isset,__call, __callStatic,__wakeup, __toString, __unset, __sleep, __invoke, __set_state i __clone.

Pot veure's una descripció i exemple del seu ús, en el lloc web oficial de PHP:

Metodes màgics php

Declaració de Classes abstractes

Les classes abstractes són aquelles que no necessiten ser instanciadas però no obstant això, seran heretades en algun moment. Es defineixen anteposant la paraula clau abstract a class:

abstract class NombreDeMiClaseAbstracta {
#...
}

Aquest tipus de classes, serà la que contingui mètodes abstractes i generalment, la seva finalitat, és la de declarar classes "genèriques” que necessiten ser declarades però a les quals, no es pot atorgar una definició precisa (d'això, s'encarregaran les classes que l'heretin).

Herència de Classes

Els objectes poden heretar propietats i mètodes d'altres objectes. Per a això, PHP permet la “extensió” (herència) de classes, que la seva característica representa la relació existent entre diferents objectes. Per definir una classe com extend d'una classe “mare” s'utilitza la paraula clau extends.

class NombreDeMiClaseMadre {
   #...
}
class NombreDeMiClaseHija extends NombreDeMiClaseMadre {
    /* aquesta classe hereta tots els mètodes i propietats de la classe mare NombreDeMiClaseMadre */
}

Declaració de Classes finals En PHP

PHP 5 incorpora classes finals que no poden ser heretades per una altra. Es defineixen anteposant la paraula clau final.

final class NombreDeMiClaseFinal {
    #aquesta classe no podrà ser heretada
}

Quin tipus de classe declarar?

Fins a aquí, han quedat en clar, quatre tipus de classes diferents: Instanciables, astractas, heretades i finals. Com saber què tipus de classe declarar? Tot dependrà, del que necessitem fer. Aquest quadre, pot servir-nos com a guia bàsica:

Necessito... Instanciable Abstracta heretada Final
Crear una classe que pugui ser instanciada i/o heretada X
Crear una classe l'objecte de la qual guarda relació amb els mètodes i propietats d'una altra classe X
Crear una classe que solament serveixi de model per a una altra classe, sense que pugui ser instanciada X
Crear una classe que pugui instanciarse però que no pugui ser heretada per cap altra classe X

Interfaces

Les interfícies són solament un conjunt de mètodes característics de diverses classes, independentment de la relació que aquestes classes mantinguin entre si. De fet, una mateixa classe, pot implementar múltiples interfícies:

interface A {}
interface B {}
interface C {}

class MiClase implements A, B, C { }

Quina és la diferència entre una interface i una classe abstracta?

En principi, existeix una diferència conceptual que a nivells “pràctics” tal vegada no és del tot clarificadora. Aquesta diferència, radica que les classes abstractes, no deixen de ser classes, les quals representen la abstracció d'un objecte seguint un ordre de relació jeràrquica entre elles: Classe B hereta de Classe A i Classe C hereta de Classe B, però no pot tenir herències múltiples, és a dir no pot heretar de més d'una classe, ja que elles, guarden una relació d'ordre jeràrquic entre si.

No obstant la diferència conceptual, podem establir clares diferències pràctiques, que ens ajudaran a assimilar millor aquests conceptes:

  • Les interfícies no poden definir propietats (de fet, no posseeixen propietats perquè a diferència de les classes abstractes no tenen relació amb un objecte, i solament els objectes tenen propietats)
  • Les interfícies no poden tenir mètodes definits amb el seu algorisme corresponent (solament poden declarar els mètodes però no poden indicar el “quin” ni el “com” fer-ho, mentre que les classes abstractes, sí poden)
  • Les interfícies no poden instanciar-se perquè no tenen referències associades a objectes, mentre que les classes abstractes no poden instanciar-se, perquè els seus objectes són “ens abstractes” que necessiten d'una classe no abstracta per definir-se amb exactitud i poder ser instanciats.
  • Tots els mètodes declarats en una interface han de ser públics, ja que la finalitat d'una interface, és brindar un àmbit públic d'un model. Les classes abstractes, poden tenir mètodes abstractes tant públics com protegits (aquells que hauran de ser obligatòriament redefenits per les classes que l'heretin) i mètodes privats que solament ella utilitzi.

El que NO han de fer les interfaces

Les interfícies no poden:

  • Tenir el mateix nom que una classe (PHP les interpreta com una classe més. Crear una interface amb el mateix nom que una classe, seria interpretat per PHP com una “re-declaració de classe”)
  • Diferents interfícies no poden tenir noms de mètodes idèntics si seran implementades per la mateixa classe

Exercici MVC

Crea utilitzant el patró de disseny MVC una aplicació per manipular les dades d'un usuari (CRUD: Create, Read, Update, Delete). Aquestes dades es guarden en un XML i es pot crear usuaris nous i esborrar-los.

https://github.com/evilnapsis/crud-one

GESTIÓN INCIDENCIAS LA MERCÈ- MVC

Se trata de crear la gestión de incidencias del instituto, es decir, en el caso que falle un ordenador, teclado, pantalla.. avisar al administrador. La pantalla principal deberá tener un Login.(habrán dos roles: role_user, role_admin)

En el caso que haga login el user, accederá a una pantalla mostrando :

  • un listado de todas las incidencias que haya enviado y estén sin resolver.(datatables)
  • un desplegable del aula y otro con diferentes componentes por defecto (teclado, pantalla...) y un campo de observaciones para añadir comentarios.
  • puede editar las incidencias y eliminarla en el caso de estar resuelta
  • "también debe almacenar la hora de envio de la incidencia."
  • "Enviará un correo electrónico al admin cuando envie una incidencia".


En el caso que se haga login con el admin, accederá a su menú mostrando:

  • un listado de todas las incidencias, conteniendo la tarea, el usuario que la ha enviado y la fecha que se ha enviado, además tendrá un botón de "Realizado" almacenando su fecha de realización.
  • tendrá un historial de todas las incidencias mostrando su fecha de envio y realización.
  • Recomendable usar Datatables para la utilización de tablas

Exercici CutreText

Es vol dissenyar un editor de text molt sencill, mínim. Es vol la definició de les classes, la seva relació, els mètodes que tindran, etc. tot utilitzant el patrò de disseny model-vista-controlador. Es vol el disseny, no la implementació. Es pot utilitzar, si es vol, l'estandard UML.