Escolar Documentos
Profissional Documentos
Cultura Documentos
PHP e MVC PDF
PHP e MVC PDF
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;
}
</body>
</html>
A Orientação a Objetos no PHP em sua 5ª versão foi totalmente reescrita do zero. Neste capítulo,
presume‐se 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 capítulo não é fornecer um guia aos conceitos da Programação Orientada a
Objetos (POO), é uma boa idéia dar uma breve olhada em alguns de seus fundamentos. A POO remonta o
conceito de agrupar código e dados juntos em unidades lógicas chamadas classes. Este processo é
usualmente conhecido como encapsulamento, ou ocultação de informações, desde que seu objetivo é
dividir uma aplicação em entidades separadas cujos componentes internos podem ser alterados sem
alterar suas interfaces. Então classes são essencialmente uma representação de um conjunto de funções
(conhecidas por métodos e variáveis (conhecidas por propriedades ou atributos) projetadas para
trabalharem juntas e fornecer uma interface específica para o mundo externo. É importante entender que
classes são apenas plantas que não podem ser usadas diretamente – elas têm que ser instanciadas em
objetos que podem interagir com o resto da aplicação.
Class myClass {
//Conteúdo aqui
}
Como você pode perceber, esse código avisa ao interpretador PHP que você está declarando uma classe
chamada myClass cujo conteúdo será normalmente uma combinação de constantes, variáveis e funções
(métodos).
Instanciando um Objeto
Uma vez que tenha declarado uma classe, você precisa instanciá‐la para obter as vantagens que ela
oferece. Isso é feito usando o construtor new:
No PHP 5, os objetos são tratados de maneira diferente dos outros tipos de variáveis. Um objeto é sempre
passado por referência ao invés de por valor. Por exemplo:
Neste caso, ambas as variáveis myClassInstance e copyInstance apontarão para o mesmo objeto.
Isso é um comportamento padrão dos objetos na maioria das linguagens, mas não era o caso no PHP 4.
Herança de classe
Um dos fundamentos chave da POO é a herança. Ela permite que uma classe estenda outra,
essencialmente para adicionar novos métodos e propriedades, bem como redefinindo‐os 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 called"
$b->test(); // Outputs "b::test called"
$b->func(); // Outputs "a::func called"
$c->test(); // Outputs "b::test called"
$d->test(); // Outputs "b::test called"
Nesse script, começamos declarando uma classe chamada “a”. Então declaramos a classe “b” que estende
“a”. Como pode ver, a classe “b” também tem o método test() que redefine aquele declarado em “a”.
Perceba que ainda podemos, no entanto, acessar os outros métodos de “a”. Por exemplo, se chamarmos
$b->func(), estamos efetivamente chamando o método func() de “a”.
class myClass {
function myFunction() {
echo "You called myClass::myFunction";
}
}
Do lado de fora do escopo de uma classe, seus métodos são chamados usando o operador ‐>:
class myClass {
function myFunction() {
echo "You called myClass::myFunction";
}
function callMyFunction() {
// ???
}
}
class myClass {
function myFunction($data) {
echo "The value is $data";
}
function callMyFunction($data) {
// Call myFunction()
$this->myFunction($data);
}
}
$obj = new myClass();
$obj->callMyFunction(123);
Construtores
O PHP introduziu o conceito de construtor unificado e, juntamente com ele, um novo destruidor de
objetos. O construtor e o destruidor são métodos especiais de classe que são chamados, como seus nomes
sugerem, na criação e destruição dos objetos, ou para executar procedimentos de inicialização. Nas versões
anteriores do PHP, construtores tinham o mesmo nome da classe. Agora, utiliza‐se o método
__construct(). Isso é útil, pois caso queira renomear a classe, não será preciso renomear os
construtores. Exercício: verifique se é possível existir mais de um método construtor na mesma classe.
class foo {
function __construct()
{
echo __METHOD__;
}
function foo()
{
// PHP 4 style constructor
}
}
new foo();
Destruidores
Além do método __construct(), temos também o método __destruct(). Ele trabalha como uma
imagem de espelho do __construct(). Ele é chamado logo antes de um objeto ser destruído e é útil
para executar operações de limpeza, como desconectar de um recurso remoto ou apagar arquivos
temporários:
class foo {
function __construct()
{
echo __METHOD__ . PHP_EOL;
}
function __destruct()
{
echo __METHOD__;
}
}
new foo();
foo::__construct
foo::__destruct
A destruição ocorre quando qualquer referência a um objeto desaparece, como no caso abaixo:
$a = new foo();
$b = $a;
unset($a);
Mesmo que um objeto ainda possua uma ou mais referências ativas, o método __destruct() é
chamado no final da execução do script, então você terá a garantia de que em algum momento seu
destruidor será executado. Entretanto, não há uma maneira de determinar a ordem de destruição de dois
ou mais objetos. Isso pode causar algum problema quando um objeto depende de outro para executar uma
ou mais funções.
Visibilidade
O PHP 5 adicionou a noção de visibilidade de métodos e propriedades de objetos , que permite que você
determine o escopo a partir do qual cada componente de sua classe possa ser acessado.
OBS: o nível de visibilidade final somente se aplica a métodos e classes. Classes que são declaradas como
final não podem ser estendidas. Normalmente, você irá querer tornar todos os métodos e propriedades de
sua API públicas, desde que queira torná‐los acessíveis de fora de seus objetos, enquanto você desejará
manter as operações internas protegidas ou privadas. Construtores e destruidores são normalmente
declarados como públicos, entretanto, às vezes você pode desejar tornar os construtores privados quando,
por exemplo, quer usar alguns padrões 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 três classes: foo, bar que estende foo e tem acesso a todos os métodos e
propriedades públicos e privados de foo e, finalmente, baz que cria uma nova instância de foo e pode
somente acessar suas propriedades públicas. Execute o programa e observe a saída.
Propriedades são 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 variável comum, uma propriedade de classe pode ser declarada e inicializada ao
mesmo tempo. Entretanto, a inicialização é limitada à associação de valores (mas não a uma avaliação de
expressão). Você não pode, por exemplo, iniciar uma propriedade chamando uma função, o que só pode
ser feito de dentro de um construtor.
class foo {
static $bar = "bat";
static public function baz()
{
echo "Hello World";
}
}
$foo = new foo();
$foo->baz();
echo $foo->bar;
foo::baz
Notice: Undefined property: foo::$bar in PHPDocument1 on line 17
É necessário para a definição de estático seguir a definição de visibilidade, ou seja, se nenhuma definição
de visibilidade é declarada, o método ou propriedade é considerado público.
Constantes de Classe
Constantes de classe funcionam da mesma forma que as constantes regulares, exceto que possuem o
escopo interno à classe. Constantes de classe são públicas e acessíveis 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 têm várias vantagens sobre as constantes tradicionais: uma vez que são encapsuladas
em uma classe, elas fazem um código muito mais limpo, e são significativamente mais rápidas do que as
declaradas com o construtor define().
(Extraído de http://apostilas.fok.com.br/manual_do_php/index.php)
class MinhaClasse {
const VALOR_CONST = 'Um valor constante';
}
$classname = 'MinhaClasse';
echo $classname::VALOR_CONST; // No PHP 5.3.0
echo MinhaClasse::VALOR_CONST;
Duas palavras‐chaves especiais self e parent são usadas para acessar membros ou métodos de dentro da
definição da classe.
Quando uma subclasse sobrecarrega a definição de um método do pai, O PHP não chamará o método pai.
Fica ao encargo da subclasse chamar o método pai ou não. Isso também se aplica a definições de métodos
Construtores e Destruidores, Sobrecarregados e Mágicos também.
class MinhaClasse {
protected function minhaFuncao() {
echo "MinhaClasse::minhaFuncao()\n";
}
}
class OutraClasse extends MinhaClasse {
/* Sobrecarrega a definição do pai */
public function minhaFuncao() {
/* Mas ainda chama a função pai */
parent::minhaFuncao();
echo "OutraClasse::minhaFuncao()\n";
}
}
$classe = new OutraClasse();
$classe->minhaFuncao();
OBS: Você deve declarar uma classe como abstrata, enquanto ela tiver (ou herdar, sem fornecer um
corpo) pelo menos um método abstrato.
Como você pode ver, neste exemplo, nós definimos uma classe chamada DataStore_Adapter e
declaramos dois métodos abstratos chamados insert() e update(). Observe como esses métodos na
verdade não têm um corpo ‐ que é um dos requisitos das classes abstratas – e como a própria classe deve
ser declarada como abstrata, para que o compilador possa satisfazer os requisitos do analisador sintático.
Em seguida, estender DataStore_Adapter em PDO_DataStore_Adapter, que já não é abstrata,
porque temos agora um corpo fornecido, tanto para insert() como para update().
Interfaces
Interfaces, por outro lado, são usadas para especificar uma API que uma classe deve implementar. Isto
permite‐lhe criar um contrato "comum" que as classes devem implementar com o propósito de satisfazer
determinados requisitos lógicos, por exemplo, você poderia usar interfaces para o conceito abstrato de
fornecedor de banco de dados em uma API comum que poderia então ser implementada em uma série de
classes que fazem interface com SGBDs diferentes. Métodos de Interface não 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ê não definir todos os métodos para uma interface em particular ou todos os
argumentos para qualquer método de determinada interface (ou seja, não tiver a mesma assinatura), você
vai ver algo como:
ou
É possível implementar mais de uma interface numa mesma classe. Bastando separá‐las por vírgula:
Lembre‐se: uma classe só pode estender uma classe pai, mas pode implementar várias interfaces.
Muitas vezes é conveniente ser capaz de determinar se um determinado objeto é uma instância de uma
determinada classe, ou se ela implementa uma interface específica. Isto pode ser feito usando o operador
instanceof:
Naturalmente, instanceof permite‐lhe inspecionar todas as classes ancestrais de seu objeto, bem
como as interfaces.
Exceções
Mesmo que tenham sido um alimento básico da programação orientada a objeto por anos, as exceções
apenas recentemente se tornaram parte do arsenal PHP. Exceções 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 várias diferenças fundamentais entre erros "regulares" de PHP e exceções:
Como mencionado no parágrafo anterior, as exceções são objetos que devem ser instâncias diretas ou
indiretas (por exemplo através de herança) da classe Exceção. Esta última é construída 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 exceção são automaticamente preenchidas para você pelo
interpretador, de modo geral, você só precisa enviar uma mensagem e um código, e todas as informações
restantes o PHP cuidará para você. Uma vez que uma exceção é uma classe comum (se embutida), você
pode estendê‐la e efetivamente criar suas próprias exceções, proporcionando assim seus manipuladores de
erro com qualquer informação adicional que sua aplicação requeira.
Lançando Exceções
As exceções são normalmente criadas e acionadas quando um erro ocorre usando a construtor throw:
OBS: Embora seja uma prática comum, você não precisa criar o objeto Exception diretamente na
expressão throw.
if ($error) {
throw new Exception ("This is my error");
}
As exceções, em seguida, "borbulham" até que sejam tratadas pelo script ou causem uma exceção fatal. O
tratamento de exceções é 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 exceção que é lançada dentro do bloco try()será capturada e passada ao
código que está dentro do bloco catch(), onde pode ser manipulada como você desejar. Observe como
o método catch() da declaração obriga‐nos a informar o tipo de exceção que queremos para o
catch(); uma das melhores características das exceções é o fato de que você pode decidir que tipo de
exceção 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:
Nesse exemplo, temos três blocos aninhados try ... catch, o mais interno só irá capturar objetos
PDOException, enquanto que o próximo vai pegar os objetos myException comuns e as regiões mais
periféricas irão capturar todas as outras exceções que poderíamos ter perdido. Ao invés de aninhar blocos
try ... catch como fizemos acima, você pode também 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 exceção tenha sido capturada, a execução do script seguirá diretamente após o último
bloco catch. Para evitar erros fatais de exceções não capturadas, você poderia envolver toda a sua
aplicação em um bloco try ... catch ‐ o que, contudo, poderia ser bastante inconveniente.
Felizmente, há uma solução melhor – o PHP nos permite definir uma função "catch-all", que é
chamada automaticamente sempre que uma exceção não é tratada. Esta função é 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 exceção "catch‐all” ser chamado apenas após a exceção ter
borbulhada por todo o script, ele, assim como um bloco abrangente try... catch, é o fim da linha para
o seu código. Em outras palavras, a exceção já causou um erro fatal, e a você será apenas dada a
oportunidade de lidar com isso, mas não recuperar a partir dela. Por exemplo, o código acima nunca terá
uma saída “You caught me!”, porque a exceção gerada irá disparar e causar o manipulador de exceção
handleUncaughtException(), fazendo com que o script termine.
OBS: Se você deseja restaurar o manipulador de exceção anteriormente usado, seja ele o padrão
de um erro fatal ou outro definido pelo usuário, você pode usar
restore_exception_handler().
Exercícios:
Construa um programa com as seguintes características: uma classe Conta abstrata com os métodos
abstratos getSaldo(), sacar(valor) e depositar(valor). A seguir, cria duas classes,
ContaCorrente e ContaPoupança, sendo que a classe ContaPoupanca deverá estender a classe
ContaCorrente, mas contendo um método remunerar(tempo) que aplicará regras de
capitalização simples, ou seja, a remuneração incide apenas sobre o montante principal, a uma taxa
constante de 10% ao mês. Não se esqueça 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, faça saques e remunere o capital da conta poupança exibindo os
valores na tela. Tente fazer sem olhar a resposta abaixo:
<?php
abstract class Conta {
public $saldo;
public abstract function getSaldo();
public abstract function sacar($valor);
public abstract function depositar($valor);
}
O que é Framework?
O que é o MVC?
Cadeia de Funcionamento
Esta é a cadeia normal de funcionamento deste padrão, em que todas as camadas são usadas, o
que nem sempre acontece:
Existe a possibilidade, bastante freqüente, de um pedido não precisar invocar o model. Basta
querer gerar conteúdo que não necessite de qualquer tipo de dados. Neste caso o controller
chamará diretamente o view. Existe também a possibilidade de não ser gerada uma view, por
exemplo: o pedido ser uma atualização de dados. Apesar de não ser necessário é recomendado
fazê‐lo, as regras de interação obrigam a que se notifique o usuário do sucesso de uma operação,
ou seja, a utilização de uma view.
Frameworks Existentes:
Existem diversas frameworks que cobrem inúmeras linguagens, algumas só para web e outras
mais genéricas:
Nota: Estes são os frameworks mais populares tendo em conta que são Software Livre, existem
outros proprietários, que obviamente não recomendo.
Primeiros passos
Para utilizar este framework basta qualquer servidor HTTP com suporte a PHP. É extremamente
provável que a aplicação que deseja desenvolver necessite de uma base de dados, estão
disponíveis os motores livres PostgreSQL, MySQL e SQLite juntamente com outros proprietários. O
primeiro passo é a instalação do framework. Nada mais simples.
Nota: Evite desenvolver a partir do seu servidor de hospedagem. Se desejar trabalhar num
ambiente semelhante a um ambiente real, será boa idéia recorrer a máquinas virtuais. Depois no
browser abrir: http://localhost/pasta_de_trabalho/index.php, se tudo correu
bem então está pronto a começar a trabalhar. Como ambiente de desenvolvimento recomendo a
IDE Eclipse com o plugin PHP Edit (ou mesmo o PDT) ou o NetBeans da SUN também com o plugin
PHP. São ferramentas bastante robustas, de fácil utilização, que completam automaticamente o
código 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 diretórios
O framework é constituído por um conjunto de diretórios por onde estão espalhados os diversos
componentes que o compõem. Ao instalar, verá que existe um diretório de documentação na raiz.
Você poderá mantê‐lo ou apagá‐lo, poderá mantê‐lo durante o desenvolvimento da aplicação,
mas deverá apagá‐lo quando disponibilizar a aplicação online, a não ser que queira disponibilizar
essa documentação online. Existe também um arquivo index.php, este tem obrigatoriamente que
existir, pois todos os pedidos à aplicação se iniciam a partir dele. Por fim, temos o diretório system
onde existem os seguintes diretórios:
Olá mundo
Para variar vamos começar com a criação de um programa Olá Mundo. A maneira mais simples de
fazê‐lo é utilizar apenas um controlador. Vá à pasta controllers e crie um arquivo chamado
primeiro.php e edite‐o. Nele escreva o seguinte código:
<?php
class Primeiro extends Controller
{
//em PHP4: function Primeiro()
function __construct()
{
parent::Controller();
}
function index()
{
echo 'Olá Mundo'
}
}
?>
function opiniao()
{
echo 'Estou a gostar muito desta ferramenta';
}
}
?>
Esta função é similar à anterior, apenas serve para demonstrar o funcionamento dos endereços.
Neste caso, para invocar esta atividade do controlador deverá digitar o endereço:
http://localhost/index.php/primeiro/opiniao
Caso não seja especificada nenhuma atividade, será sempre executada a função 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". Altere‐a para o endereço que você vai utilizar em seu aplicativo. Por
exemplo: “http://localhost/pasta_de_trabalho”.
Views
As views são arquivos PHP que contêm código HTML e chamadas PHP responsáveis pela
apresentação dos dados. No exemplo anterior eram os controladores que apresentavam qualquer
conteúdo na página, o que não é prático nem segue a norma MVC, pelo que vamos fazer algumas
alterações. Primeiro vamos acrescentar uma nova view, no diretório views crie o arquivo
mensagem.php com o seguinte conteúdo:
<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 serão passadas
duas variáveis: title que definirá o título a aparecer na janela do browser e message que terá
a mensagem que aparecerá na página web. Para utilizar a view vamos alterar ambas as ações 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 opinião';
$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 é necessário
criar um vetor associativo em que o índice terá correspondência a uma variável com o mesmo
nome na view. A última linha de cada atividade é uma chamada à view onde o primeiro parâmetro
corresponde ao nome do arquivo da view (a extensão PHP pode ser omitida), e o segundo
corresponde à estrutura com os dados a serem passados. Não há qualquer obrigação de passar
dados para uma view, pelo que nestes casos deverá apenas invocar a view apenas com o primeiro
parâmetro. Para uma view podem ser passados dados de qualquer tipo, sejam eles numéricos,
texto, objetos ou outras estruturas de dados. O próximo exemplo demonstra como passar um
vetor para a view e como este normalmente é tratado. Crie uma nova view chamada
topics.php com o seguinte conteúdo:
<html>
<head>
<title>Uma lista de tópicos</title>
</head>
<body>
<ul>
<?php foreach($topics as $topic): ?>
<li><?php echo $topic ?></li>
<?php endforeach ?>
</ul>
</body>
</html>
Aqui a única diferença é que é usado um ciclo foreach para escrever cada um dos elementos na
página. Para pôr esta view para funcionar necessitamos criar uma atividade no nosso controlador
que o invoque, por isso vamos adicionar a função topics() no arquivo primeiro.php:
function topics()
{
$data['topics'] = array('Model', 'View', 'Controller');
$this->load->view('topics', $data);
}
Nada mais simples. No diretório views é possível criar subdiretórios para organizá‐las. Para invocar
essas views deverá incluir o nome do diretório na sua chamada:
$this->load->view('directory/topics');
E assim terminamos este capítulo, no próximo serão abordados o uso de bases de dados e os
modelos.
Acesso a dados
Depois de termos dado uma visão global ao padrão MVC e de dar os primeiros passos com o
framework CodeIgniter, abordaremos uma parte também importante de uma aplicação web: o
acesso a bases de dados.
Ao contrário de alguns frameworks, como por exemplo, o Symfony, o Django, etc., o CodeIgniter
não possui nenhum mecanismo próprio para criação de bases de dados, à semelhança do que
acontece no Ruby on Rails ou no CakePHP, motivo pelo qual teremos que criá‐lo. O CodeIgniter
segue um padrão de acesso a dados conhecido como Active Record que será demonstrado mais à
frente. Para este capítulo, apenas iremos utilizar a seguinte tabela utilizando o MySQL:
$active_group = "default";
$active_record = TRUE;
$db['default']['hostname'] = "localhost";
$db['default']['username'] = "root";
$db['default']['password'] = "";
$db['default']['database'] = "ads01";
$db['default']['dbdriver'] = "mysql";
$db['default']['dbprefix'] = "";
$db['default']['pconnect'] = TRUE;
$db['default']['db_debug'] = TRUE;
$db['default']['cache_on'] = FALSE;
$db['default']['cachedir'] = "";
$db['default']['char_set'] = "utf8";
$db['default']['dbcollat'] = "utf8_general_ci";
O arquivo em si não tem muito que saber. Basta alterar o valor de cada elemento com os dados
respectivos. Para seguir este tutorial será necessário ter a variável $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 automático da classe ou carregá‐la 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 automático
//para carregamento automático editar config/autoload.php
//e adicionar 'database' ao array $autoload['libraries']
$autoload['libraries'] = array('database');
Para verificar se a conexão à base de dados está funcionando basta executar o seu browser e abrir
o url da sua aplicação. Se não foi informado algum erro, então está tudo ok.
Nota: A escolha de utilização de carregamento automático ou não classes está dependente do tipo
de projeto. Se for uma classe utilizada por todos os controladores recomenda‐se o carregamento
automático de modo a poupar algum esforço. Se essa classe apenas for utilizada por algumas
funcionalidades então recomendo que se faça o carregamento apenas quando necessárias para
evitar sobrecarregar os controladores com material desnecessário.
A exibição de dados é certamente a tarefa mais comum em aplicações 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 não for escrito retorna 0
$username = $this->uri->segment(3,0);
if($username == 0)
{
//se o id não 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);
}
}
}
?>
user/all:
<h1>Lista de usuários</h1>
<table>
<tr>
<th>Username</th>
<th>Email</th>
<th></th>
</tr>
user/show:
Os registros devolvidos são armazenados numa estrutura em memória da qual se pode extrair
cada um deles como instância de um objeto Active Record, como neste exemplo, ou
alternativamente num array associativo. Neste exemplo foram usados dois métodos: result()
e row(). O método result(), usado na view user/all gera uma lista de objetos row, cada
um deles representa um registro. O método 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 método row() devolverá apenas a primeira linha.
Neste exemplo utilizou‐se o helper url. Esse fornece, entre outras, a função anchor que nos
permite criar hyperlinks de forma dinâmica para outras funcionalidades da nossa aplicação. No
exemplo acima podemos ver que esta é utilizada para criar ligações para a página show de cada
registro. Outra função a destacar que utilizamos é a função uri->segment que extrai
elementos da nossa url, neste caso o username. O segundo parâmetro é opcional e indica o valor
por omissão caso se invoque essa funcionalidade sem fornecer o username.
Modelos
Como foi explicado no primeiro tutorial, no padrão MVC o Model é responsável pela abstração do
acesso a dados. O que se passa no CodeIgniter é que o padrão Active Record já faz isso de uma
forma mais geral. É possível criar um projeto sem ter que implementar classes do tipo modelo,
mas para casos mais específicos, como consultas mais complexas, é recomendado implementar
essas funções numa classe Model. Podemos reestruturar o exemplo anterior tendo em conta os
seguintes aspectos:
<?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 funções que retornam os resultados apenas com os dados que
desejamos exibir. O método select da classe db encarrega‐se de definir os campos a retornar
pela próxima consulta à base de dados. Agora falta‐nos 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 não 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);
}
}
}
?>
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);
}
?>
<?php
function register()
{
//definição da lista de regras a aplicar
$config=array(
array(
'field' => 'username',
'label' => 'Nome de Usuário',
'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' => 'Confirmação de Palavra Passe',
'rules' => 'required'
),
array(
'field' => 'email',
'label' => 'E-mail',
'rules' => 'required|valid_email'
)
);
?>
Nesse exemplo, recorremos ao método de criar um array com todas as regras de validação a
aplicar. Nesse array, cada elemento possui três campos: