Sunteți pe pagina 1din 27

Introduo Linguagem PHP

Manipulando erros em PHP


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title></title> </head> <body> <?php function myErrorHandler($errno, $errstr, $errfile, $errline) { switch ($errno) { case E_NOTICE: case E_USER_NOTICE: $errors = "Notice"; break; case E_WARNING: case E_USER_WARNING: $errors = "Ateno"; break; case E_ERROR: case E_USER_ERROR: $errors = "Fatal Error"; break; default: $errors = "Desconhecido"; break; } if (ini_get("display_errors")) printf ("<br />\n<b>%s</b>: %s em <b>%s</b> na linha <b>%d</b><br /><br />\n", $errors, $errstr, $errfile, $errline); if (ini_get('log_errors')) error_log(sprintf("PHP %s: %s in %s on line %d", $errors, $errstr, $errfile, $errline)); return true; } // Configurar o manipulador de erros set_error_handler("myErrorHandler"); // Forar um erro de diviso por ZERO echo 4/0; ?> </body> </html>

Programao Orientada a Objeto em PHP


(Extrado do Livro Zend PHP 5 Certification Study Guide)
A Orientao a Objetos no PHP em sua 5 verso foi totalmente reescrita do zero. Neste captulo, presumese que o aluno esteja familiarizado com os conceitos de OO para que possa usufruir de seu poder aplicado ao PHP.

Fundamentos de POO
Enquanto o objetivo deste captulo no fornecer um guia aos conceitos da Programao Orientada a Objetos (POO), uma boa idia dar uma breve olhada em alguns de seus fundamentos. A POO remonta o conceito de agrupar cdigo e dados juntos em unidades lgicas chamadas classes. Este processo usualmente conhecido como encapsulamento, ou ocultao de informaes, desde que seu objetivo dividir uma aplicao em entidades separadas cujos componentes internos podem ser alterados sem alterar suas interfaces. Ento classes so essencialmente uma representao de um conjunto de funes (conhecidas por mtodos e variveis (conhecidas por propriedades ou atributos) projetadas para trabalharem juntas e fornecer uma interface especfica para o mundo externo. importante entender que classes so apenas plantas que no podem ser usadas diretamente elas tm que ser instanciadas em objetos que podem interagir com o resto da aplicao.

Declarando uma classe


A declarao bsica de uma classe muito simples: Class myClass { //Contedo aqui } Como voc pode perceber, esse cdigo avisa ao interpretador PHP que voc est declarando uma classe chamada myClass cujo contedo ser normalmente uma combinao de constantes, variveis e funes (mtodos).

Instanciando um Objeto
Uma vez que tenha declarado uma classe, voc precisa instancila para obter as vantagens que ela oferece. Isso feito usando o construtor new: $myInstance = new myClass(); No PHP 5, os objetos so tratados de maneira diferente dos outros tipos de variveis. Um objeto sempre passado por referncia ao invs de por valor. Por exemplo: $myClassInstance = new myClass(); $copyInstance = $myClassInstance(); Neste caso, ambas as variveis myClassInstance e copyInstance apontaro para o mesmo objeto. Isso um comportamento padro dos objetos na maioria das linguagens, mas no era o caso no PHP 4.

Herana de classe
Um dos fundamentos chave da POO a herana. Ela permite que uma classe estenda outra, essencialmente para adicionar novos mtodos e propriedades, bem como redefinindoos caso j existentes. Por exemplo: class a { function test() { echo "a::test called"; } function func() {

echo "a::func called"; } } class b extends a { function test() { echo "b::test called"; } } class c extends b { function test() { parent::test(); } } class d extends c { function test() { b::test(); } } $a = new a(); $b = new b(); $c = new c(); $d = new d(); $a->test(); // Outputs "a::test $b->test(); // Outputs "b::test $b->func(); // Outputs "a::func $c->test(); // Outputs "b::test $d->test(); // Outputs "b::test

called" called" called" called" called"

Nesse script, comeamos declarando uma classe chamada a. Ento declaramos a classe b que estende a. Como pode ver, a classe b tambm tem o mtodo test() que redefine aquele declarado em a. Perceba que ainda podemos, no entanto, acessar os outros mtodos de a. Por exemplo, se chamarmos $b->func(), estamos efetivamente chamando o mtodo func() de a.

Mtodos e propriedades de classe


Como mencionado anteriormente, classes podem conter mtodos e variveis (propriedades). Mtodos so declarados do mesmo jeito das funes tradicionais: class myClass { function myFunction() { echo "You called myClass::myFunction"; } } Do lado de fora do escopo de uma classe, seus mtodos so chamados usando o operador >: $obj = new myClass(); $obj->myFunction(); Realemente, a varivel $obj s vlida dentro do escopo de nosso pequeno trecho de cdigo acima que nos deixa com um dilema: como referenciar um mtodo de classe de dentro da prpria classe? Aqui vai um exemplo: class myClass { function myFunction() {

echo "You called myClass::myFunction"; } function callMyFunction() { // ??? } } Claramente, callMyFunction() precisa de uma maneira de chamar myFunction() de dentro do escopo do objeto. Para que isso seja possvel, o PHP dispe de uma varivel especial chamada $this. Ele sempre se refere ao prprio objeto. Exemplo: class myClass { function myFunction($data) { echo "The value is $data"; } function callMyFunction($data) { // Call myFunction() $this->myFunction($data); } } $obj = new myClass(); $obj->callMyFunction(123); Este trecho de cdigo mostrar The value is 123.

Construtores
O PHP introduziu o conceito de construtor unificado e, juntamente com ele, um novo destruidor de objetos. O construtor e o destruidor so mtodos especiais de classe que so chamados, como seus nomes sugerem, na criao e destruio dos objetos, ou para executar procedimentos de inicializao. Nas verses anteriores do PHP, construtores tinham o mesmo nome da classe. Agora, utilizase o mtodo __construct(). Isso til, pois caso queira renomear a classe, no ser preciso renomear os construtores. Exerccio: verifique se possvel existir mais de um mtodo construtor na mesma classe. class foo { function __construct() { echo __METHOD__; } function foo() { // PHP 4 style constructor } } new foo();

Destruidores
Alm do mtodo __construct(), temos tambm o mtodo __destruct(). Ele trabalha como uma imagem de espelho do __construct(). Ele chamado logo antes de um objeto ser destrudo e til para executar operaes de limpeza, como desconectar de um recurso remoto ou apagar arquivos temporrios: class foo { function __construct()

{ echo __METHOD__ . PHP_EOL; } function __destruct() { echo __METHOD__; } } new foo(); Esse cdigo mostrar: foo::__construct foo::__destruct A destruio ocorre quando qualquer referncia a um objeto desaparece, como no caso abaixo: $a = new foo(); $b = $a; unset($a); Mesmo que um objeto ainda possua uma ou mais referncias ativas, o mtodo __destruct() chamado no final da execuo do script, ento voc ter a garantia de que em algum momento seu destruidor ser executado. Entretanto, no h uma maneira de determinar a ordem de destruio de dois ou mais objetos. Isso pode causar algum problema quando um objeto depende de outro para executar uma ou mais funes.

Visibilidade
O PHP 5 adicionou a noo de visibilidade de mtodos e propriedades de objetos , que permite que voc determine o escopo a partir do qual cada componente de sua classe possa ser acessado.

public O recurso pode ser acessado a partir de qualquer escopo. protected O recurso s pode ser acessado de dentro da classe onde est definido ou a partir
de seus descendentes. private O recurso s pode ser acessado de dentro da classe onde est definido. final O recurso pode ser acessado a partir de qualquer escopo, mas no pode ser redefinido ou sobrecarregado.

OBS: o nvel de visibilidade final somente se aplica a mtodos e classes. Classes que so declaradas como final no podem ser estendidas. Normalmente, voc ir querer tornar todos os mtodos e propriedades de sua API pblicas, desde que queira tornlos acessveis de fora de seus objetos, enquanto voc desejar manter as operaes internas protegidas ou privadas. Construtores e destruidores so normalmente declarados como pblicos, entretanto, s vezes voc pode desejar tornar os construtores privados quando, por exemplo, quer usar alguns padres de projeto como o Singleton ou Factory: class foo { public $foo = bar; protected $baz = bat; private $qux = bingo; function __construct() { var_dump(get_object_vars($this)); } }

class bar extends foo { function __construct() { var_dump(get_object_vars($this)); } } class baz { function __construct() { $foo = new foo(); var_dump(get_object_vars($foo)); } } new foo(); new bar(); new baz(); O exemplo acima cria trs classes: foo, bar que estende foo e tem acesso a todos os mtodos e propriedades pblicos e privados de foo e, finalmente, baz que cria uma nova instncia de foo e pode somente acessar suas propriedades pblicas. Execute o programa e observe a sada.

Declarando e Acessando Propriedades


Propriedades so declaradas em PHP orientado a objetos usando um dos modificadores de acesso mencionados anteriormente, seguido de seus respectivos nomes: class foo { public $bar; protected $baz; private $bas; public var1 = "Test"; // String public var2 = 1.23; // Numeric value public var3 = array (1, 2, 3); } Observe que, como uma varivel comum, uma propriedade de classe pode ser declarada e inicializada ao mesmo tempo. Entretanto, a inicializao limitada associao de valores (mas no a uma avaliao de expresso). Voc no pode, por exemplo, iniciar uma propriedade chamando uma funo, o que s pode ser feito de dentro de um construtor.

Constantes, Mtodos e Propriedades Estticos


Juntamente com o PPP, o PHP 5 tambm implementa mtodos e propriedades estticos. Ao contrrio dos mtodos e propriedades regulares, os seus correspondentes estticos existem e so acessveis como parte de uma classe em si, em oposio ao existente apenas no mbito de uma das suas instncias. Isto permite tratlas como verdadeiras contineres de funes e dados interrelacionados o que, por sua vez, um expediente muito til para evitar conflitos de nomes. Enquanto o PHP 4 permitia que voc chamasse qualquer mtodo de uma classe esttica usando o escopo operador de resoluo:: (oficialmente conhecido como Paamayim Nekudotayimhebraico para Colon "Double"), o PHP 5 introduz uma sintaxe mais rigorosa que apela para o uso da palavrachave static para transmitir a utilizao de propriedades e mtodos como tal. Voc deve ter em mente que o PHP 5 muito rigoroso sobre o uso de propriedades e mtodos estticos. Por exemplo, chamar propriedades estticas usando a notao de objeto resultar em uma mensagem de erro: class foo { static $bar = "bat";

static public function baz() { echo "Hello World"; } } $foo = new foo(); $foo->baz(); echo $foo->bar; Isso ir mostrar: foo::baz Notice: Undefined property: foo::$bar in PHPDocument1 on line 17 necessrio para a definio de esttico seguir a definio de visibilidade, ou seja, se nenhuma definio de visibilidade declarada, o mtodo ou propriedade considerado pblico.

Constantes de Classe
Constantes de classe funcionam da mesma forma que as constantes regulares, exceto que possuem o escopo interno classe. Constantes de classe so pblicas e acessveis a partir de qualquer escopo. Por exemplo, o seguinte script mostrar Hello World: class foo { const BAR = "Hello World"; } echo foo::BAR; Constantes de classe tm vrias vantagens sobre as constantes tradicionais: uma vez que so encapsuladas em uma classe, elas fazem um cdigo muito mais limpo, e so significativamente mais rpidas do que as declaradas com o construtor define().

Operador de Resoluo de Escopo (::)


(Extrado de http://apostilas.fok.com.br/manual_do_php/index.php) O Operador de Resoluo de Escopo, tambm chamado de Paamayim Nekudotayim, ou em termos mais simples, dois pontos duplo, um token que permite acesso a mtodos ou membros estticos, constantes, e sobrecarregados de uma classe. Quando referenciando esses itens de fora da definio da classe, voc usa o nome da classe. No PHP 5.3.0, possvel referenciar o nome da classe usando uma varivel. O valor da varivel no pode ser uma palavra chave (e.g. self, parent e static). Paamayim Nekudotayim pode parecer de incio uma escolha estranha para um dois pontos duplo. No entanto, na hora de escrever o Engine da Zend 0.5 (que provia o PHP3), foi o que a equipe da Zend decidiu. Realmente significa dois pontos duplo em Hebreu! Exemplo #1 :: de fora da definio da classe class MinhaClasse { const VALOR_CONST = 'Um valor constante'; } $classname = 'MinhaClasse'; echo $classname::VALOR_CONST; // No PHP 5.3.0 echo MinhaClasse::VALOR_CONST;

Duas palavraschaves especiais self e parent so usadas para acessar membros ou mtodos de dentro da definio da classe. Exemplo #2 :: de dentro da definio da classe class OutraClasse extends MinhaClasse { public static $meu_estatico = 'varivel esttica'; public static function doisPontosDuplo() { echo parent::VALOR_CONST . "\n"; echo self::$meu_estatico . "\n"; } } $classname = 'OutraClasse'; echo $classname::doisPontosDuplo(); // No PHP 5.3.0 OutraClasse::doisPontosDuplo(); Quando uma subclasse sobrecarrega a definio de um mtodo do pai, O PHP no chamar o mtodo pai. Fica ao encargo da subclasse chamar o mtodo pai ou no. Isso tambm se aplica a definies de mtodos Construtores e Destruidores, Sobrecarregados e Mgicos tambm. Exemplo #3 Chamando um mtodo pai class MinhaClasse { protected function minhaFuncao() { echo "MinhaClasse::minhaFuncao()\n"; } } class OutraClasse extends MinhaClasse { /* Sobrecarrega a definio do pai */ public function minhaFuncao() { /* Mas ainda chama a funo pai */ parent::minhaFuncao(); echo "OutraClasse::minhaFuncao()\n"; } } $classe = new OutraClasse(); $classe->minhaFuncao();

Interfaces e Classes Abstratas


Outro novo recurso adicionado ao PHP 5 o de interfaces e classes abstratas. Elas so usadas para criar uma srie de restries sobre a concepo bsica de um grupo de classes. Uma classe abstrata define essencialmente o esqueleto bsico de um tipo especfico de entidade encapsulada. Por exemplo, voc pode usar uma classe abstrata para definir uma base conceitual de um "carro" como tendo duas portas, um mtodo de fechar ou abrir portas. Classes abstratas no podem ser usadas diretamente, mas devem ser estendidas para que a classe descendente fornea um conjunto completo de mtodos. Por exemplo: abstract class DataStore_Adapter { private $id; abstract function insert(); abstract function update(); public function save() { if (!is_null($this->id)) { $this->update(); } else { $this->insert();

} } } class PDO_DataStore_Adapter extends DataStore_Adapter { public __construct($dsn) { // ... } function insert() { // ... } function update() { // ... } } OBS: Voc deve declarar uma classe como abstrata, enquanto ela tiver (ou herdar, sem fornecer um corpo) pelo menos um mtodo abstrato. Como voc pode ver, neste exemplo, ns definimos uma classe chamada DataStore_Adapter e declaramos dois mtodos abstratos chamados insert() e update(). Observe como esses mtodos na verdade no tm um corpo que um dos requisitos das classes abstratas e como a prpria classe deve ser declarada como abstrata, para que o compilador possa satisfazer os requisitos do analisador sinttico. Em seguida, estender DataStore_Adapter em PDO_DataStore_Adapter, que j no abstrata, porque temos agora um corpo fornecido, tanto para insert() como para update().

Interfaces
Interfaces, por outro lado, so usadas para especificar uma API que uma classe deve implementar. Isto permitelhe criar um contrato "comum" que as classes devem implementar com o propsito de satisfazer determinados requisitos lgicos, por exemplo, voc poderia usar interfaces para o conceito abstrato de fornecedor de banco de dados em uma API comum que poderia ento ser implementada em uma srie de classes que fazem interface com SGBDs diferentes. Mtodos de Interface no podem conter nenhum corpo: interface DataStore_Adapter { public function insert(); public function update(); public function save(); public function newRecord($name = null); } class PDO_DataStore_Adapter implements DataStore_Adapter { public function insert() { // ... } public function update() { // ... } public function save() { // ...

} public function newRecord($name = null) { } } Se, no exemplo acima, voc no definir todos os mtodos para uma interface em particular ou todos os argumentos para qualquer mtodo de determinada interface (ou seja, no tiver a mesma assinatura), voc vai ver algo como: Fatal error: Class PDO_DataStore_Adapter contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (DataStore_Adapter::save) in //document// on line 27 ou Fatal error: Declaration of PDO_DataStore_Adapter::newRecord() must be compatible with that of DataStore_Adapter::newRecord() in //document// on line 12 possvel implementar mais de uma interface numa mesma classe. Bastando separlas por vrgula: class PDO_DataStore_Adapter implements DataStore_Adapter, SeekableIterator { // ... } Lembrese: uma classe s pode estender uma classe pai, mas pode implementar vrias interfaces. class PDO_DataStore_Adapter extends PDO implements DataStore_Adapter, SeekableIterator { // ... }

Determinando Uma classe de objeto


Muitas vezes conveniente ser capaz de determinar se um determinado objeto uma instncia de uma determinada classe, ou se ela implementa uma interface especfica. Isto pode ser feito usando o operador instanceof: if ($obj instanceof MyClass) { echo "\$obj is an instance of MyClass"; } Naturalmente, instanceof permitelhe inspecionar todas as classes ancestrais de seu objeto, bem como as interfaces.

Excees
Mesmo que tenham sido um alimento bsico da programao orientada a objeto por anos, as excees apenas recentemente se tornaram parte do arsenal PHP. Excees fornecem um mecanismo de controle de erro que mais refinado do que o tratamento de falhas tradicional do PHP, e que permite um grau muito maior de controle. Existem vrias diferenas fundamentais entre erros "regulares" de PHP e excees: As excees so objetos, criados (ou "lanados") quando ocorre um erro;

Excees podem ser tratadas em diferentes pontos na execuo de um script, e diferentes tipos de Excees podem ser tratadas por partes separadas de um cdigo de script; Todas as excees no so fatais; Excees podem ser lanadas a partir do mtodo __construct() em caso de falha; Excees alteram o fluxo do aplicativo.

A classe Exception Bsica


Como mencionado no pargrafo anterior, as excees so objetos que devem ser instncias diretas ou indiretas (por exemplo atravs de herana) da classe Exceo. Esta ltima construda no PHP em si, e declarada como segue: class Exception { // The error message associated with this exception protected $message = Unknown Exception; // The error code associated with this exception protected $code = 0; // The pathname of the file where the exception occurred protected $file; // The line of the file where the exception occurred protected $line; // Constructor function __construct ($message = null, $code = 0); // Returns the message final function getMessage(); // Returns the error code final function getCode(); // Returns the file name final function getFile(); // Returns the file line final function getLine(); // Returns an execution backtrace as an array final function getTrace(); // Returns a backtrace as a string final function getTraceAsString(); // Returns a string representation of the exception function __toString(); } Quase todas as propriedades de uma exceo so automaticamente preenchidas para voc pelo interpretador, de modo geral, voc s precisa enviar uma mensagem e um cdigo, e todas as informaes restantes o PHP cuidar para voc. Uma vez que uma exceo uma classe comum (se embutida), voc pode estendla e efetivamente criar suas prprias excees, proporcionando assim seus manipuladores de erro com qualquer informao adicional que sua aplicao requeira.

Lanando Excees
As excees so normalmente criadas e acionadas quando um erro ocorre usando a construtor throw: OBS: Embora seja uma prtica comum, voc no precisa criar o objeto Exception diretamente na expresso throw. if ($error) { throw new Exception ("This is my error"); }

As excees, em seguida, "borbulham" at que sejam tratadas pelo script ou causem uma exceo fatal. O tratamento de excees feita usando um bloco try ... catch: try { if ($error) { throw new Exception ("This is my error"); } } catch (Exception $e) { // Handle exception } No exemplo acima, qualquer exceo que lanada dentro do bloco try()ser capturada e passada ao cdigo que est dentro do bloco catch(), onde pode ser manipulada como voc desejar. Observe como o mtodo catch() da declarao obriganos a informar o tipo de exceo que queremos para o catch(); uma das melhores caractersticas das excees o fato de que voc pode decidir que tipo de exceo capturar. Desde que voc livre para estender a Classe pai Exception, isso significa que diferentes blocos aninhados try ... catch podem ser usados para interceptar e lidar com diferentes tipos de erros: class myException extends Exception { } try { try { try { new PDO("mysql:dbname=zce"); throw new myException("An unknown error occurred."); } catch (PDOException $e) { echo $e->getMessage(); } } catch(myException $e) { echo $e->getMessage(); } } catch (Exception $e) { echo $e->getMessage(); } Nesse exemplo, temos trs blocos aninhados try ... catch, o mais interno s ir capturar objetos PDOException, enquanto que o prximo vai pegar os objetos myException comuns e as regies mais perifricas iro capturar todas as outras excees que poderamos ter perdido. Ao invs de aninhar blocos try ... catch como fizemos acima, voc pode tambm apenas encadear os blocos catch: try { new PDO("mysql:dbname=zce"); throw new myException("An unknown error occurred."); } catch (PDOException $e) { echo $e->getMessage(); } catch (myException $e) { echo $e->getMessage(); } catch (Exception $e) { echo $e->getMessage(); } Uma vez que uma exceo tenha sido capturada, a execuo do script seguir diretamente aps o ltimo bloco catch. Para evitar erros fatais de excees no capturadas, voc poderia envolver toda a sua aplicao em um bloco try ... catch o que, contudo, poderia ser bastante inconveniente. Felizmente, h uma soluo melhor o PHP nos permite definir uma funo "catch-all", que

chamada automaticamente sempre que uma exceo no tratada. Esta funo configurada chamando set_exception_handler(): function handleUncaughtException($e) { echo $e->getMessage(); } set_exception_handler("handleUncaughtException"); throw new Exception("You caught me!"); echo "This is never displayed"; Note que, devido o manipulador de exceo "catchall ser chamado apenas aps a exceo ter borbulhada por todo o script, ele, assim como um bloco abrangente try... catch, o fim da linha para o seu cdigo. Em outras palavras, a exceo j causou um erro fatal, e a voc ser apenas dada a oportunidade de lidar com isso, mas no recuperar a partir dela. Por exemplo, o cdigo acima nunca ter uma sada You caught me!, porque a exceo gerada ir disparar e causar o manipulador de exceo handleUncaughtException(), fazendo com que o script termine.

OBS: Se voc deseja restaurar o manipulador de exceo anteriormente usado, seja ele o padro de um erro fatal ou outro definido pelo usurio, voc pode usar restore_exception_handler().

Exerccios:
Construa um programa com as seguintes caractersticas: uma classe Conta abstrata com os mtodos abstratos getSaldo(), sacar(valor) e depositar(valor). A seguir, cria duas classes, ContaCorrente e ContaPoupana, sendo que a classe ContaPoupanca dever estender a classe ContaCorrente, mas contendo um mtodo remunerar(tempo) que aplicar regras de capitalizao simples, ou seja, a remunerao incide apenas sobre o montante principal, a uma taxa constante de 10% ao ms. No se esquea de definir a classe Conta como abstrata e de inicializar as duas classes (ContaPoupanca e ContaCorrente) com um saldo inicial. Instancie ambas as classes com um valor inicial de R$100,00, exiba os saldos, faa saques e remunere o capital da conta poupana exibindo os valores na tela. Tente fazer sem olhar a resposta abaixo: <?php abstract class Conta public $saldo; public abstract public abstract public abstract }

{ function getSaldo(); function sacar($valor); function depositar($valor);

class ContaCorrente extends Conta { public function __construct($valor) { $this->saldo = $valor; } public function getSaldo() { return $this->saldo; } public function sacar($valor) { if ($valor > $this->getSaldo()) $this->saldo-=$valor; else echo "IMPOSSVEL DEBITAR ESSE VALOR"; } public function depositar($valor) {

if ($valor < 0) echo "Voc no pode sacar esse valor!"; else $this->saldo+=$valor; } } class ContaPoupanca extends ContaCorrente { private static $taxa = 0.1; //10% ao ms public function __construct($valor) { $this->saldo = $valor; } public function remunera($tempo) { $this->saldo += $this->saldo*(self::$taxa * $tempo); } } $c1 = new ContaCorrente(100); $c2 = new ContaPoupanca(100); echo $c1->depositar(10); echo $c1->getSaldo(); echo "<hr />"; echo $c2->depositar(20); echo $c2->remunera(2); echo $c2->getSaldo(); ?>

Introduo ao MVC com CodeIgniter e PHP


Encontrei esse tutorial sobre MVC que utiliza um framework para permitir maior produtividade no desenvolvimento de software em PHP, conforme exigido na prtica profissional da disciplina. Este tutorial foi extrado do endereo http://programadoranonimo.blogspot.com/ e adaptado ao portugus brasileiro. Este tutorial tem como objetivo abordar o desenvolvimento de aplicaes web seguindo uma arquitetura conhecida como arquitetura MVC Model, View, Controller. A ferramenta utilizada neste tutorial ser o framework CodeIgniter.

O que Framework?
Em desenvolvimento de software, um framework ou arcabouo uma abstrao que une cdigos comuns entre vrios projetos de software provendo uma funcionalidade genrica. Um framework pode atingir uma funcionalidade especfica, por configurao, durante a programao de uma aplicao. Ao contrrio das bibliotecas, o framework quem dita o fluxo de controle da aplicao, chamado de Inverso de Controle. Ainda, framework um conjunto de classes que colaboram para realizar uma responsabilidade para um domnio de um subsistema da aplicao. (Extrado da Wikipdia)

O que o MVC?
O MVC, Model View Controller, um padro de desenvolvimento de aplicaes, normalmente, mas no forosamente, web. A implementao de aplicaes usando este padro so feitas com recurso a frameworks, apesar de no ser obrigatria a utilizao de um para seguir o padro.

Camadas e respectivas funes

Model: Nesta camada so definidas as regras de acesso e manipulao dos dados, que normalmente so armazenados em bases de dados ou arquivos, mas nada indica que sirva s para alojamento persistente dos dados. Pode ser usado para dados em memria voltil, por exemplo: memria RAM, apesar no se verificar tal utilizao com muita freqncia. Todas as regras relacionadas com tratamento, obteno e validao dos dados devem ser implementados nesta camada. View: Esta camada responsvel por gerar a forma como a resposta ser apresentada, pgina web, formulrio, relatrio, etc. Controller: a camada responsvel por responder aos pedidos por parte do usurio. Sempre que um usurio faz um pedido ao servidor esta camada a primeira a ser executada.

Cadeia de Funcionamento
Esta a cadeia normal de funcionamento deste padro, em que todas as camadas so usadas, o que nem sempre acontece: 1. 2. 3. 4. 5. O usurio efetua um pedido ao servidor O controller processa o pedido do usurio. O controller efetua uma chamada ao model, para obter ou manipular dados. O model devolve os dados pedidos que sero passados ao view. A view gera a apresentao dos dados, por exemplo: uma pgina HTML.

Existe a possibilidade, bastante freqente, de um pedido no precisar invocar o model. Basta querer gerar contedo que no necessite de qualquer tipo de dados. Neste caso o controller chamar diretamente o view. Existe tambm a possibilidade de no ser gerada uma view, por exemplo: o pedido ser uma atualizao de dados. Apesar de no ser necessrio recomendado fazlo, as regras de interao obrigam a que se notifique o usurio do sucesso de uma operao, ou seja, a utilizao de uma view.

Frameworks Existentes:
Existem diversas frameworks que cobrem inmeras linguagens, algumas s para web e outras mais genricas:

PHP: CodeIgniter, CakePHP, Symfony, Zend Framework, etc. Ruby: Ruby on Rails, etc. Python: Django, Zope, TuboGears, etc. Java: J2EE, Spring Framework, etc. Mono/.NET: Monorail, etc.

Nota: Estes so os frameworks mais populares tendo em conta que so Software Livre, existem outros proprietrios, que obviamente no recomendo.

Por que o CodeIgniter?


A resposta curta: porque simplesmente estou utilizandoo no momento. A resposta comprida: os critrios para o tutorial foram os mesmos para o meu projeto. A questo da linguagem caiu obviamente para o PHP, quer pela sua popularidade em aplicaes web, quer pelo fato de ser

bastante fcil obter servios de alojamento que o suportem. Quanto ao framework, j utilizei o Symfony e j brinquei com o CakePHP e estou agora a utilizar o CodeIgniter. A escolha deste framework recaiu sobre os seguintes critrios: simples e com um desempenho bastante bom e a sua abordagem bastante mais direta que o CakePHP e o Symfony. Esta ltima mais complexa, apesar de no ser de todo uma desvantagem. Escolhi o CodeIgniter por ter a "melhor relao custo/qualidade".

Primeiros passos
Para utilizar este framework basta qualquer servidor HTTP com suporte a PHP. extremamente provvel que a aplicao que deseja desenvolver necessite de uma base de dados, esto disponveis os motores livres PostgreSQL, MySQL e SQLite juntamente com outros proprietrios. O primeiro passo a instalao do framework. Nada mais simples.

Fazer o download do framework em http://codeigniter.com/download.php Descomprimir o arquivo. E copiar o contedo do diretrio CodeIgniter_x.x.xx para o seu diretrio web.

Nota: Evite desenvolver a partir do seu servidor de hospedagem. Se desejar trabalhar num ambiente semelhante a um ambiente real, ser boa idia recorrer a mquinas virtuais. Depois no browser abrir: http://localhost/pasta_de_trabalho/index.php, se tudo correu bem ento est pronto a comear a trabalhar. Como ambiente de desenvolvimento recomendo a IDE Eclipse com o plugin PHP Edit (ou mesmo o PDT) ou o NetBeans da SUN tambm com o plugin PHP. So ferramentas bastante robustas, de fcil utilizao, que completam automaticamente o cdigo e que funcionam bem com este framework. Podem fazer download a partir do site oficial e instalar o plugin PHP posteriormente, ou fazer o download personalizado com as funcionalidades que desejar no site yoxos.

Estrutura de diretrios
O framework constitudo por um conjunto de diretrios por onde esto espalhados os diversos componentes que o compem. Ao instalar, ver que existe um diretrio de documentao na raiz. Voc poder mantlo ou apaglo, poder mantlo durante o desenvolvimento da aplicao, mas dever apaglo quando disponibilizar a aplicao online, a no ser que queira disponibilizar essa documentao online. Existe tambm um arquivo index.php, este tem obrigatoriamente que existir, pois todos os pedidos aplicao se iniciam a partir dele. Por fim, temos o diretrio system onde existem os seguintes diretrios:

application: este ser o diretrio onde far o desenvolvimento da sua aplicao. Em condies normais ser o nico a sofrer alteraes durante o desenvolvimento. cache: o cache do sistema, onde so criados arquivos temporrios que permitem o aumento da performance da aplicao. codeigniter: o "motor" do framework. database: controladores de base de dados. fonts: tipos de letra. helpers: colees de funes de auxilio ao desenvolvimento que, por exemplo, podero ajudar a criar elementos de uma pgina de uma forma mais simples. language: arquivos com termos usados pela framework numa determinada lngua. Instalao do Portugus padro.

library: biblioteca com as classes de referncia que podem ser utilizadas no desenvolvimento da aplicao. logs: logs de sistema plugins: similar aos helpers, s que em vez de uma coleo de funes os plugins apenas disponibilizam uma funo. scaffolding: motor de scaffolding. Permite a gerar automaticamente pginas de visualizao, criao, edio e eliminao de dados a partir de tabelas da base de dados. Esta ferramenta apenas deve ser utilizada durante o desenvolvimento, pois no oferece qualquer garantia de segurana. Este modelo de scaffolding deixou de ser oficialmente suportado e ser substitudo, pelo que no dever ser abordado para j nesta srie de tutoriais.

Dentro da pasta application temos um conjunto de diretrios orientado para o desenvolvimento da aplicao. Os diretrios helpers, languages e libraries so equivalentes aos que encontramos no diretrio system, mas neste caso destinamse a componentes criados especificamente para o seu projeto. Os diretrios restantes so os seguintes:

config: arquivos de configurao. controllers: local onde criar os seus controllers. errors: pginas de erro personalizadas, como por exemplo o famoso 404Not Found hooks: extenses ao CodeIgniter, onde poder criar funes ou classes que sero executadas em determinados momentos do fluxo de processamento da aplicao. models: local onde criar os seus models. views: local onde criar as suas views.

Ol mundo Para variar vamos comear com a criao de um programa Ol Mundo. A maneira mais simples de fazlo utilizar apenas um controlador. V pasta controllers e crie um arquivo chamado primeiro.php e editeo. Nele escreva o seguinte cdigo:
<?php class Primeiro extends Controller { //em PHP4: function Primeiro() function __construct() { parent::Controller(); } function index() { echo 'Ol Mundo' } } ?>

Se digitar no seu web browser o endereo http://localhost/index.php/primeiro obter uma pgina com o texto Ol Mundo. O exemplo comea pela declarao de uma classe que herda as caractersticas de classe do CodeIgniter Controller, todos os controllers so subclasses de Controller, o nome da classe e do arquivo so iguais, a nica diferena que o nome da classe deve comear sempre com maiscula. Depois temos duas funes: a funo Primeiro() o construtor da classe, que neste caso apenas chama o construtor da sua

superclasse, este pode ser usado para carregar qualquer tipo de componente do sistema; a segunda funo uma atividade do controlador, normalmente todos os controladores tm uma funo index que chamada sempre que esse controlador invocado sem que seja invocada qualquer funo. Vamos acrescentar mais uma funo ao nosso controlador:
<?php class Primeiro extends Controller { (...) function opiniao() { echo 'Estou a gostar muito desta ferramenta'; } } ?>

OBS: o PHP 5 utiliza o construtor __construct(). Esta funo similar anterior, apenas serve para demonstrar o funcionamento dos endereos. Neste caso, para invocar esta atividade do controlador dever digitar o endereo:
http://localhost/index.php/primeiro/opiniao

A estrutura padro dos endereos :


...index.php/Nome do Controlador/Atividade/Informao complementar

Caso no seja especificada nenhuma atividade, ser sempre executada a funo index, como no primeiro exemplo, pelo que dever existir sempre um index em cada controlador. OBS: Agora, bom configurar o arquivo config.php na pasta config dentro da pasta application. Nela, existe uma linha $config['base_url'] = "http://example.com". Alterea para o endereo que voc vai utilizar em seu aplicativo. Por exemplo: http://localhost/pasta_de_trabalho. Views As views so arquivos PHP que contm cdigo HTML e chamadas PHP responsveis pela apresentao dos dados. No exemplo anterior eram os controladores que apresentavam qualquer contedo na pgina, o que no prtico nem segue a norma MVC, pelo que vamos fazer algumas alteraes. Primeiro vamos acrescentar uma nova view, no diretrio views crie o arquivo mensagem.php com o seguinte contedo:
<html> <head> <title><?php echo $title ?></title> </head> <body> <h1><?php echo $message ?></h1> </body> </html>

Esta view ser invocada por ambos os controladores e como podemos observar sero passadas duas variveis: title que definir o ttulo a aparecer na janela do browser e message que ter a mensagem que aparecer na pgina web. Para utilizar a view vamos alterar ambas as aes do controlador.
<?php class Primeiro extends Controller { //em PHP4: function Primeiro() function __construct() { parent::Controller(); } function index() { $data['title']='Primeiro Exemplo'; $data['message']='Ol Mundo!'; $this->load->view('mensagem',$data); } function opiniao() { $data['title']='A minha opinio'; $data['message']='Estou a gostar muito desta ferramenta'; $this->load->view('mensagem',$data); } } ?>

Agora o funcionamento ficou ligeiramente alterado. Para passar dados a uma view necessrio criar um vetor associativo em que o ndice ter correspondncia a uma varivel com o mesmo nome na view. A ltima linha de cada atividade uma chamada view onde o primeiro parmetro corresponde ao nome do arquivo da view (a extenso PHP pode ser omitida), e o segundo corresponde estrutura com os dados a serem passados. No h qualquer obrigao de passar dados para uma view, pelo que nestes casos dever apenas invocar a view apenas com o primeiro parmetro. Para uma view podem ser passados dados de qualquer tipo, sejam eles numricos, texto, objetos ou outras estruturas de dados. O prximo exemplo demonstra como passar um vetor para a view e como este normalmente tratado. Crie uma nova view chamada topics.php com o seguinte contedo:
<html> <head> <title>Uma lista de tpicos</title> </head> <body> <ul> <?php foreach($topics as $topic): ?> <li><?php echo $topic ?></li> <?php endforeach ?> </ul> </body> </html>

Aqui a nica diferena que usado um ciclo foreach para escrever cada um dos elementos na pgina. Para pr esta view para funcionar necessitamos criar uma atividade no nosso controlador que o invoque, por isso vamos adicionar a funo topics() no arquivo primeiro.php:

function topics() { $data['topics'] = array('Model', 'View', 'Controller'); $this->load->view('topics', $data); }

Nada mais simples. No diretrio views possvel criar subdiretrios para organizlas. Para invocar essas views dever incluir o nome do diretrio na sua chamada:
$this->load->view('directory/topics');

E assim terminamos este captulo, no prximo sero abordados o uso de bases de dados e os modelos.

Acesso a dados
Depois de termos dado uma viso global ao padro MVC e de dar os primeiros passos com o framework CodeIgniter, abordaremos uma parte tambm importante de uma aplicao web: o acesso a bases de dados.

Criao da base de dados e configurar o acesso


Ao contrrio de alguns frameworks, como por exemplo, o Symfony, o Django, etc., o CodeIgniter no possui nenhum mecanismo prprio para criao de bases de dados, semelhana do que acontece no Ruby on Rails ou no CakePHP, motivo pelo qual teremos que crilo. O CodeIgniter segue um padro de acesso a dados conhecido como Active Record que ser demonstrado mais frente. Para este captulo, apenas iremos utilizar a seguinte tabela utilizando o MySQL:
CREATE TABLE `users` ( `id` int(11) NOT NULL auto_increment, `username` varchar(20) character set latin1 NOT NULL, `passwd` varchar(40) character set latin1 NOT NULL, `salt` varchar(40) character set latin1 NOT NULL, `email` varchar(100) character set latin1 NOT NULL, PRIMARY KEY (`id`) );

Agora vamos configurar o acesso base de dados no CodeIgniter, dentro do diretrio application/config editem o arquivo database.php:
$active_group = "default"; $active_record = TRUE; $db['default']['hostname'] $db['default']['username'] $db['default']['password'] $db['default']['database'] $db['default']['dbdriver'] $db['default']['dbprefix'] $db['default']['pconnect'] $db['default']['db_debug'] $db['default']['cache_on'] $db['default']['cachedir'] $db['default']['char_set'] $db['default']['dbcollat'] = = = = = = = = = = = = "localhost"; "root"; ""; "ads01"; "mysql"; ""; TRUE; TRUE; FALSE; ""; "utf8"; "utf8_general_ci";

O arquivo em si no tem muito que saber. Basta alterar o valor de cada elemento com os dados respectivos. Para seguir este tutorial ser necessrio ter a varivel $active_record fixada como TRUE. O passo seguinte ser configurar o acesso classe de base de dados. Isto pode ser feito de dois modos: ativar o carregamento automtico da classe ou carregla no construtor de cada Controller ou Model:
//---Carregamento "Manual"--//em cada controlador ou modelo invocar //$this->load->database() class User extends Controller { //em PHP4: function Nome() function __construct() { parent::Controller(); $this->load->database(); } } //---Carregamento automtico //para carregamento automtico editar config/autoload.php //e adicionar 'database' ao array $autoload['libraries'] $autoload['libraries'] = array('database');

Para verificar se a conexo base de dados est funcionando basta executar o seu browser e abrir o url da sua aplicao. Se no foi informado algum erro, ento est tudo ok. Nota: A escolha de utilizao de carregamento automtico ou no classes est dependente do tipo de projeto. Se for uma classe utilizada por todos os controladores recomendase o carregamento automtico de modo a poupar algum esforo. Se essa classe apenas for utilizada por algumas funcionalidades ento recomendo que se faa o carregamento apenas quando necessrias para evitar sobrecarregar os controladores com material desnecessrio.

Ler registros da base de dados


A exibio de dados certamente a tarefa mais comum em aplicaes web. Para demonstrar como realizar este tipo de tarefas vamos criar duas atividades num controlador User em controllers/user.php:

user/all user/show/$id

Para testar este exemplo recomendo que introduzam alguns dados na tabela users:
<?php class User extends Controller { function __construct() { parent::Controller(); $this->load->helper('url'); } function all() { //selecciona todos os registros de users

$data['list']=$this->db->get('users'); //envia a lista de dados para a view $this->load->view('user/all',$data); } function show() { //vai buscar o id ao url, 3 elemento //se no for escrito retorna 0 $username = $this->uri->segment(3,0); if($username == 0) { //se o id no foi fornecido redireciona redirect('user/all'); } else { $result = $this->db->get_where( 'users', array('username' => $username)); //selecciona a nica linha do resultado $data['user'] = $result->row(); $this->load->view('user/show',$data); } } } ?>

E agora as duas user/all e user/show: user/all:


<h1>Lista de usurios</h1> <table> <tr> <th>Username</th> <th>Email</th> <th></th> </tr> <?php foreach($list->result() as $user): ?> <tr> <td><?php echo $user->username ?></td> <td><?php echo $user->email ?></td> <td><?php echo anchor('user/show/'.$user->username);?></td> </tr> <?php endforeach ?> </table>

user/show:
<p><b>Username:</b> <?php echo $user->username ?></p> <p><b>E-mail:</b> <?php echo $user->email ?></p>

Os mtodos mais importantes para este exemplo so:

$this->db->get('tabela'): Devolve todos os dados da tabela (SELECT * FROM tabela)

$this->db->get_where('tabela', critrios): seleciona todos os registro que correspondam a um critrio.

Os registros devolvidos so armazenados numa estrutura em memria da qual se pode extrair cada um deles como instncia de um objeto Active Record, como neste exemplo, ou alternativamente num array associativo. Neste exemplo foram usados dois mtodos: result() e row(). O mtodo result(), usado na view user/all gera uma lista de objetos row, cada um deles representa um registro. O mtodo row() extrai diretamente uma linha, o que muito til para casos como este em que a consulta base de dados devolve uma nica linha, caso devolva mais que uma linha o mtodo row() devolver apenas a primeira linha. Neste exemplo utilizouse o helper url. Esse fornece, entre outras, a funo anchor que nos permite criar hyperlinks de forma dinmica para outras funcionalidades da nossa aplicao. No exemplo acima podemos ver que esta utilizada para criar ligaes para a pgina show de cada registro. Outra funo a destacar que utilizamos a funo uri->segment que extrai elementos da nossa url, neste caso o username. O segundo parmetro opcional e indica o valor por omisso caso se invoque essa funcionalidade sem fornecer o username.

Modelos
Como foi explicado no primeiro tutorial, no padro MVC o Model responsvel pela abstrao do acesso a dados. O que se passa no CodeIgniter que o padro Active Record j faz isso de uma forma mais geral. possvel criar um projeto sem ter que implementar classes do tipo modelo, mas para casos mais especficos, como consultas mais complexas, recomendado implementar essas funes numa classe Model. Podemos reestruturar o exemplo anterior tendo em conta os seguintes aspectos:

Estamos requisitando tabela todos os campos de um registro quando apenas utilizamos dois deles Podemos criar mtodos para obter os dados prontos a ser exibidos, encurtando o tamanho dos nossos controladores

Para isso vamos criar uma classe user_model.php no diretrio models:


<?php class User_model extends Model { function getDisplayableByUsername($username) { //indica os campos $this->db->select('username, email'); $result = $this->db->get_where( 'users', array('username' => $username)); return $result->row(); } function getAllDisplayable() { $this->db->select('username, email'); $result = $this->db->get('users'); return $result->result(); } }

Neste exemplo, criamos duas funes que retornam os resultados apenas com os dados que desejamos exibir. O mtodo select da classe db encarregase de definir os campos a retornar pela prxima consulta base de dados. Agora faltanos alterar o controlador para utilizar o model.
<?php class User extends Controller { function __construct() { parent::Controller(); $this->load->helper('url'); $this->load->model('user_model'); } function all() { //selecciona todos os registros de users //a ser exibidos $data['list'] = $this->user_model->getAllDisplayable(); $this->load->view('user/all',$data); } function show() { //vai buscar o id ao url, 3 elemento //se no for escrito retorna 0 $username = $this->uri->segment(3,0); if($username == 0) { redirect('user/all'); } else { $data['user'] = $this->user_model->GetDisplayableByUsername($username); $this->load->view('user/show',$data); } } } ?>

Para completar, como o mtodo GetAllDisplayable() j retorna uma lista result, devemos ir ao cdigo da view user/all e remover a chamada ao mtodo result() no ciclo foreach para que tudo funcione devidamente.

Inserir dados, Formulrios e Validao


No que diz respeito validao, ser usado o novo sistema form_validation introduzido na verso 1.7.0. Em qualquer pgina web com validao de dados existe o seguinte ciclo de validao: 1. 2. 3. 4. Pedir os dados ao usurio; Verificar os dados; Caso os dados no sejam vlidos exibir erros e voltar ao ponto um; Tratar os dados.

Comeando pela solicitao de dados, vamos criar uma view user/register.php com o seguinte contedo:
<?php echo validation_errors() ?> <?php echo form_open('user/register') ?> <fieldset> <label for="username">Usurio: </label> <input type="text" id="username" value="" /> <label for="password">Palavra-Passe:</label> <input type="password" id="password" value="" /> <label for="confirm">Confirmar:</label> <input type="password" id="confirm" value="" /> <label for="email">E-mail</label> <input type="text" id="email" value="" /> </fieldset> <input type="submit" value="Enviar" /> </form>

A view acima um formulrio tpico em PHP/HTML. Na primeira linha sero impressas as mensagens de erro caso a validao dos dados falhe. Recorrese tambm funo form_tag para gerar uma tag form que chamar o controlador responsvel por validar e armazenar os dados. Agora para armazenar os dados restanos criar o controlador para o efeito. Mas antes disso vamos preparar a nossa classe modelo para guardar este tipo de dados. Lembrese que estamos a criar um formulrio para registro de usurios e dados sensveis como a password no sero armazenados no formato em que so inseridos. A palavra passe ser transformada antes de ser armazenada recorrendo funo de hashing sha1 utilizando uma chave salt para impedir a obteno da senha atravs de dicionrios de hash conhecidos. Ao modelo user_model.php sero acrescentados os seguintes mtodos:
<?php private function hashPassword($password) { //gera uma string salt aleatria $data['salt'] = sha1(rand()); //gera o hashing da password $data['password'] = sha1($data['salt'].$password); return $data; } function register() { $data['username'] = $this->input->post('username'); $hash = $this->hashPassword($this->input->post('passwd')); $data['passwd'] = $hash['password']; $data['salt'] = $hash['salt']; $data['email'] = $this->input->post('email'); $this->db->insert('users', $data); } ?>

O mtodo register guarda os dados, depois de codificar a password. Usando o mtodo insert do Active Record a insero de dados no poderia ser mais simples, basta um array associativo em que o ndice corresponde ao nome do campo na tabela e depois passlo como argumento da funo insert. Para obter os dados enviados pelo formulrio podem usar o mtodo $this->input->post('nome') ou acessar diretamente ao respectivo elemento no

array post: $_POST['nome']. O mtodo hashPassword responsvel apenas por gerar um hash e um salt para a senha. Por fim, no controlador user, vamos criar um mtodo register que, neste exemplo, ser responsvel por criar as regras e executar o ciclo de validao:
<?php function register() { //definio da lista de regras a aplicar $config=array( array( 'field' => 'username', 'label' => 'Nome de Usurio', 'rules' => 'required|min_length[4]|max_length[20]' ), array( 'field' => 'passwd', 'label' => 'Palavra Passe', 'rules' => 'required|min_length[6]|matches[confirm]' ), array( 'field' => 'confirm', 'label' => 'Confirmao de Palavra Passe', 'rules' => 'required' ), array( 'field' => 'email', 'label' => 'E-mail', 'rules' => 'required|valid_email' ) ); //atribui a lista de regras prxima execuo da validao $this->form_validation->set_rules($config); //Teste de validao de dados if(($this->form_validation->run())==FALSE) { //caso a validao no tenha tido sucesso //ou ainda no foi invocada $this->load->view('user/register'); } else { //se a validao teve sucesso $this->user_model->register(); //redirecciona para uma pgina de sucesso redirect('user/success'); } } ?>

Nesse exemplo, recorremos ao mtodo de criar um array com todas as regras de validao a aplicar. Nesse array, cada elemento possui trs campos:

field: possui o nome do campo a avaliar, dever obrigatoriamente corresponder ao id do elemento do formulrio que fornecer esses dados. label: contm uma identificao do campo, compreensvel pelos usurios, a aparecer na mensagem de erro.

rules: aqui so declaradas as regras a ser aplicadas ao campo, as mais comuns so: required, campo obrigatrio; min_length/max_length, definem os limites de tamanho em caracteres dos dados inseridos; valid_email, endereo de correio eletrnico vlido, etc.

A estrutura if no exemplo garante a execuo do ciclo de validao. Na primeira chamada ao controlador, invocada pelo usurio, a validao falha sempre sem qualquer erro, por isso exibida a view com o formulrio. O usurio ao enviar os dados faz com que o controlador seja de novo invocado e a validao executada. Se falhar ser reexibido o formulrio com as respectivas mensagens de erro. Caso os dados estejam corretamente inseridos, sero guardados na base de dados. Aps o armazenamento o controlador os redireciona para uma pgina de sucesso que no foi listada neste exemplo, dada a sua simplicidade deixoa ao critrio de cada um.

S-ar putea să vă placă și