Anda di halaman 1dari 69

Introdução ao

desenvolvimento
com Spaghetti*
Aprenda a desenvolver com
produtividade e diversão
por Julio Gre e Rafael Marin
Seja bem vindo ao mundo do desenvolvimento Web

Olá! divertido. Desenvolver Web já foi chato e


desmotivador. Hoje, com Spaghetti*, o seu trabalho
pode ser mais excitante a cada novo dia. Esteja você
começando no mundo do desenvolvimento, ou
começando a pensar sobre como você tem
desenvolvido ultimamente, ou ainda procurando um
framework pequeno mas totalmente extensível,
Spaghetti* é para você.

Spaghetti* é desenvolvido por pessoas que amam a


Internet, e que sobretudo pensam que ela é, na
verdade, uma rede de pessoas. O framework é
escrito e testado em projetos reais de clientes reais
com necessidades reais. Desde o início. É pouca
teoria e muita prática. É menos reunião e mais
produção. É menos projeto e mais resultado.

A Internet é um meio que muda muito. Então você,


desenvolvedor, tem à sua disposição uma ferramenta
que entende não somente o fato de que haverão
mudanças durante o processo de desenvolvimento,
mas também entende que você, como ser humano,
comete erros. Vendemos com o Spaghetti* não
apenas uma ferramenta, mas uma filosofia. Uma
filosofia de desenvolvimento produtivo e divertido,
com qualidade de código.

O Spaghetti* tem feito nosso dia melhor, e


acreditamos que ele também pode fazer o seu e de
sua equipe.

Um forte abraço da
equipe do Spaghetti*
Seja bem vindo!
Seja bem vindo ao primeiro livro do Spaghetti*! Aqui você
pode descobrir um pouco mais sobre nosso framework, suas
características e funcionalidades. Seja uma pequena dúvida ou
uma grande curiosade, você encontrará aqui!

Além de entregar um framework de qualidade, também nos


preocupamos em mantê-lo bem documentado, para que qualquer um
possa aprender a usá-lo, e tornar seu trabalho cada vez melhor. O
resultado é essa documentação em formato de livro que, apesar de se
manter simples, é compreensiva o bastante para cobrir todos os
aspectos pertinentes do Spaghetti*.

Começando
Se você é novo no mundo do Spaghetti*, pode começar descobrindo um
pouco mais sobre este framework, o que ele faz e por que você pode
usá-lo. Mas se você já é mais experiente e sabe o que procurar, pode se
guiar pela documentação on-line, ou ainda conhecer o código-fonte do
Spaghetti* de perto.

Como obter ajuda


Caso este libro não seja suficiente, você encontra em nosso site
tutoriais e screencasts, além da documentação mais atualizada.
Introdução sobre MVC
O Spaghetti* foi construído baseando-se no design pattern
MVC, separando as camadas da sua aplicação, tornando o
desenvolvimento e manutenção muito mais fáceis e rápidos.
Na prática, toda a camada de lógica e dados fica separada da
camada de apresentação de sua aplicação, mantendo seu
código PHP longe do código HTML, fazendo com que
designers e programadores possam trabalhar
simultaneamente de maneira harmoniosa e eficiente.

Modelos de Dados
Os modelos de dados, ou Models, representam os dados de sua
aplicação. Embora os dados geralmente venham de bancos de dados
como MySQL, SQL Server e similares, eles podem ser basicamente
qualquer coisa, desde arquivos de texto até documentos em XML. O
limite é a sua criatividade.

As classes do Spaghetti* irão auxiliá-lo na manipulação de seus dados,


sem que você precise escrever uma única linha de SQL. O Spaghetti* faz
o trabalho sujo, enquanto você se preocupa com o que realmente
interessa.

No momento, os modelos de dados do Spaghetti* funcionam apenas


com MySQL, embora o suporte a outros bancos de dados já esteja
previsto para a próxima versão. Isso também significa que, se não existir
um driver para o banco de dados que você usa, você mesmo poderá
criá-lo e compartilhar com a comunidade do Spaghetti*.

Controladores
É nos Controllers que a mágica realmente acontece. É aqui onde você irá
tratar as respostas do usuário, buscar e processar dados e retorná-los
para as Views. Nada de código HTML, nada de CSS, nada de JavaScript.
Única e puramente código PHP.
Mesmo você estando no comando, o Spaghetti* irá lhe auxiliar dando
acesso aos seus Models e facilitando o envio de dados para as Views.
Você se diverte programando, e o Spaghetti* o ajuda com o resto.

Visualizações
As Views fazem parte da camada de apresentação de sua aplicação.
Nessa camada você se preocupa unicamente em mostrar os dados ao
usuário, usando apenas algumas estruturas básicas em PHP, evitando
aquela típica mistura de lógica e apresentação em um mesmo arquivo.
Além disso, também é possível usar comandos para a criação fácil de
links, imagens e formulários, sem que você precise se preocupar com
detalhes chatos de implementação.

Escolhemos o MVC por ser um pattern que faz bastante sentido no


desenvolvimento Web, além de aumentar a produtividade, diminuir a
repetição de código, facilitar a correção de bugs e tornar a vida dos
desenvolvedores um pouco mais divertida. E você, está pronto para
entrar brincadeira, e se unir a nós por um desenvolvimento melhor?
Configurando sua aplicação
Gigantescos arquivos de configuração? Não nesse framework.
Qualquer aplicação do Spaghetti* já está pronta para ser
desenvolvida em questão de segundos!

Configurar o Spaghetti* é realmente muito fácil. Embora algumas outras


configurações sejam possíveis, a única coisa que você necessita para ter
uma aplicação rodando é definir as configurações de seu banco de
dados.

Configurando o banco de dados


Para configurar seu banco de dados, você precisa editar o arquivo
app/config/database.php. O Spaghetti* já vem com uma configuração
de exemplo, você só precisa alterar os campos necessários, e sua
configuração ficará assim:

$database = array(
"development" => array(
"host" => "localhost",
"user" => "username",
"password" => "password",
"database" => "spaghetti",
"prefix" => ""
)
);

O Spaghetti* suporta configurações diferentes para cada ambiente de


desenvolvimento. No exemplo acima, definimos o ambiente
development, mas também podemos definir quantos mais forem
necessários. Isso evita que você sobrescreva configurações, facilitando o
deploy da aplicação.

Escolhendo o Ambiente
Para escolher o ambiente que você deseja usar, basta alterar a
configuração environment no arquivo app/config/settings.php:
Config::write("environment", "development");

E o que mais?
Apesar de você poder customizar um pouco mais sua aplicação, você
não precisa mais nada para começar sua aplicação. O Spaghetti* prefere
convenção em vez de configuração, e todo o resto é deduzido através da
estrutura do framework. Agora você está pronto pra começar a
trabalhar!
Rotas
URLs complicadas, sem sentido ou apenas longas demais são
um problema comum. Entretanto, com as rotas do Spaghetti*
a solução é simples e rápida, e você nem mesmo precisará
escrever mais do que algumas linhas!

Nem sempre a estrutura padrão controller/action/id é a melhor ou


mais indicada para sua aplicação. Embora faça sentido, você pode
precisar fazer suas próprias modificações nessa estrutura. Esse é o
propósito do arquivo app/config/routes.php.

Rotas Padrão
Quando você abrir o arquivo de configuração de rotas, você já
encontrará uma chamada ao método Mapper::connect(), definindo a
rota padrão de sua aplicação.

Mapper::connect("/", "/home");

A rota acima vinculará a raiz de sua aplicação com o HomeController.


Essa rota pode apontar para qualquer outro controller de sua aplicação,
mas ela é necessária pois o Spaghetti* precisa saber como proceder
quando nenhum controller é especificado na URL. Caso contrário, será
chamada a classe Controller, que é apenas uma classe base, e não um
controller propriamente dito.

Definindo novas rotas


A definição de novas rotas modificará a resposta de sua aplicação de
acordo com a URL acessada. As rotas devem ser definidas no mesmo
arquivo app/config/routes.php, pois ele é chamado antes de qualquer
processamento do Spaghetti*.

Para conectar novas rotas a determinadas URLs, utilizamos o método


Mapper::connect(), que deve receber dois parâmetros: o padrão a ser
comparado e a rota que esse padrão deve seguir. Ou seja, o padrão será
a URL acessada, e a rota será o caminho que essa URL terá. Com a rota
abaixo, por exemplo, a URL /posts/definindo-novas-rotas aponta
para /posts/view/definindo-novas-rotas:

Mapper::connect("/posts/:any", "/posts/view/$1");

O Mapper::connect() tem suporte a expressões regulares, tornando a


comparação ainda mais poderosa. Entretanto, para evitar que você tenha
que escrever expressões, o Spaghetti* já possui algumas strings
“mágicas” para os casos mais comuns:

:any corresponde a qualquer caracter, incluindo barras


:num corresponde a qualquer número, mas não inclui barras
:part corresponde a qualquer caracter, seja ele dígito ou número,
mas não considera barras

Para recuperar essas ocorrências depois, usamos a mesma sintaxe usada


em expressões regulares: $1 retorna a primeira ocorrência, $2 retorna a
segunda ocorrência, e assim sucessivamente.

Nota: Para que expressões regulares sejam retornadas depois, é


necessário que estejam entre parênteses.

Definindo prefixos
Várias aplicações necessitam de áreas distintas dentro de sua estrutura.
Mais do que apenas controllers diferentes, às vezes se torna necessário
realizar as mesmas ações, mas por usuários com permissões diferentes.
Isso acontece quando é necessária uma seção para administração, por
exemplo.

Para esse tipo de necessidade, o Spaghetti* conta com prefixos, através


do método Mapper::prefix():
Mapper::prefix("admin");

Quando um prefixo é definido, o Spaghetti* passa a chamar actions


diferentes. Quando a URL /admin/users for chamada, será chamada a
action admin_index de UsersController, em vez de apenas index.
Com essas ações distintas, é possível manter níveis de permissão, além
da possibilidade de alterar o comportamento de cada ação.

Nota: Prefixos também estão sujeitos a ação de rotas, ou seja, uma


rota pode redirecionar um prefixo e causar problemas em sua
aplicação.

Caso você queira definir vários prefixos, também é possível fazê-lo com
apenas uma chamada ao método, passando vários argumentos:

Mapper::prefix("admin", "user");

Através da criação de múltiplos prefixos você pode segmentar sua


aplicação, criando várias áreas distintas, com uma estrutura flexível e
bem definida.
Models
Você não precisa escrever tanto SQL. Os modelos de dados do
Spaghetti*, além de facilitarem a iteração entre registros,
também geram todo o SQL necessário para as suas consultas,
através de arrays simples, apenas com código PHP.

Os models do Spaghetti são os responsáveis por todas as tarefas de


banco de dados. Desde criar e alterar registros até buscas complexas e
relacionamentos entre tabelas, sem escrever uma única linha de SQL.
Mas não se preocupe: caso você precise ser ainda mais específico, você
também pode digitar diretamente suas consultas.

Criando Modelos
Dentro da estrutura de arquivos do Spaghetti*, os modelos se encontram
em app/models, e seguem a convenção nome_do_modelo.php.
Basicamente, um modelo é apenas uma definição de classe vazia:

class Users extends AppModel { }

Através da extensão da classe AppModel, Users herda todos os métodos


necessários para qualquer operação de banco de dados. Além disso, o
Spaghetti* já assume que o nome da tabela do banco de dados
associada a esse modelo chama-se users. Entretanto, caso você use
nomes de tabelas diferentes dos nomes dos modelos, é possível definir
o nome manualmente através da variável table.

class Users extends AppModel {


public $table = "users_table";
}

Buscando Registros
findAll( mixed $conditions, mixed $order, string $limit,
integer $recursion )

mixed Array ou string contendo as condições para a


$conditions busca
Array ou string que define a ordenação dos
mixed $order
registros
string $limit Limite de registros a serem recuperados
integer
Número de recursões para tabelas relacionadas
$recursion

O método Model::findAll() retorna todos os registros que obedeçam à


condição $conditions especificada, ordenados por $order, limitando a
$limit registros.

O parâmetro $conditions pode ser uma string SQL qualquer, como


username = "admin" ou text LIKE "%spaghetti%". Entretanto, você
não estaria usando de todo o potencial do Spaghetti*. Através de arrays,
é possível criar uma gama enorme de condições diferentes.

$conditions = array(
"username" => "admin",
"text LIKE" => "%spaghetti%"
);

// equivalente a
// username = "admin" AND text LIKE "%spaghetti%"

$this->Users->findAll($conditions);

Além de consultas simples como as usadas acima, o Spaghetti* também


permite condições mais complexas, como você pode descobrir em
Condições Complexas.

A ordenação de registros funciona de maneira semelhante, utilizando


strings ou arrays. Arrays seguem a seguinte estrutura:

$order = array("id" => "ASC", "date" => "DESC");


O retorno do método é um array contendo vários outros arrays, tendo
como chaves os nomes dos campos, pronto para uso em blocos for e
foreach, como qualquer outro array.

Array
(
[0] => Array
(
[id] => 1
[name] => admin,
[password] => spaghettiphp
)
[1] => Array
(
[id] => 2
[name] => root,
[password] => root
)
[2] => Array
(
[id] => 3
[name] => user
[password] => 123456
)
)

find( mixed $conditions, mixed $order, integer


$recursion )

mixed Array ou string contendo as condições para a


$conditions busca
Array ou string que define a ordenação dos
mixed $order
registros
integer
Número de recursões para tabelas relacionadas
$recursion

O método Model::find() funciona exatamente como Model::findAll(),


exceto por retornar apenas o primeiro registro que obedeça às
condições passadas. A estrutura do array também é ligeiramente
diferente, sendo unidimensional:

Array
(
[id] => 1,
[username] => admin
[password] => spaghettiphp
)

findAllBy( string $field, string $value, mixed $conditions,


mixed $order, string $limit, integer $recursion )

string $field Campo a ser utilizado como condicional


string $value Valor usado como condição para o campo
mixed Array ou string contendo condições adicionais
$conditions para a busca
Array ou string que define a ordenação dos
mixed $order
registros
string $limit Limite de registros a serem recuperados
integer
Número de recursões para tabelas relacionadas
$recursion

Model::findAllBy() busca todos os registros em que $field seja igual a


$value, usando $conditions como parâmetros adicionais. Seu retorno
é idêntico a Model::findAll(). Esse método é útil quando se quer usar
apenas um campo como condição para a busca:

$this->Users->findAllBy("level", "admin");

Apesar do propósito da função ser a busca por apenas um campo, é


possível adicionar outros campos como condições adicionais, tornando a
busca um pouco mais específica:

$this->Users->findAllBy("level", "user", array("approved"


=> true));

Também é possível utilizar um atalho para essa função,


Model::findAllBy<field>(), onde $field é definido no próprio nome da
função, e suprimido da lista de argumentos. Assim, $value se torna o
primeiro argumento.
$this->Users->findAllByLevel("user", array("approved"
=> true));

findBy( string $field, string $value, mixed $conditions,


mixed $order, integer $recursion )

string $field Campo a ser utilizado como condicional


string $value Valor usado como condição para o campo
mixed Array ou string contendo condições adicionais
$conditions para a busca
Array ou string que define a ordenação dos
mixed $order
registros
integer
Número de recursões para tabelas relacionadas
$recursion

Model::findBy() funciona como Model::findAllBy(), exceto por


retornar apenas o primeiro item encontrado, em um array
unidimensional.

Assim como Model::findAllBy(), também aceita o atalho


Model::findAllBy<field>():

$this->Users->findAllById(1);

Salvando Registros
save( array $data )

array $data Dados a serem salvos

O salvamento de registros é sempre algo complicado. Primeiro é


necessário saber se um registro existe, para depois podermos decidir se
ele deve ser inserido ou se deve ser apenas atualizado. Com o
Spaghetti*, você se preocupa apenas em enviar os dados, e o resto é
trabalho do framework.
Para que o Spaghetti* possa salvar corretamente os dados, o array $data
deve ser construído assim:

Array
(
[id] => 1,
[username] => admin
[password] => spaghettiphp
)

Caso algum campo não seja passado, ele não será considerado na
consulta SQL, ou seja, ele permanecerá intacto na tabela, caso exista. Se
você passar algum campo inexistente, ele será completamente
desconsiderado, então não é necessário se preocupar em limpar arrays
vindos de formulários.

Para que o modelo possa descobrir se o registro já existe na tabela, é


necessário que seja passado o campo id. É realizada uma busca na
tabela, e caso outro registro com mesma identificação já exista, ele é
atualizado. Caso contrário, ele é criado. Tudo isso na mesma função,
sem você precisar se preocupar.

Quando estiver usando Model::save() dentro de loops, não esqueça


de usar Model->create() para evitar que os dados sejam
sobrescritos.

created e modified

Muitas vezes é necessário manter registro das datas de criação e


modificação de um registro. Para que você não precise explicitamente
definir valor para esses campos, o Spaghetti* faz isso para você.

Para que esse comportamento seja usado, é necessário ter os campos


created ou modied definidos como DATETIME em sua tabela. O campo
created é definido apenas uma vez, na criação do registro, e somente
caso não tenha um valor já definido em $data. Já o campo modified é
redefinido a cada salvamento do registro, também somente caso não
esteja definido em $data.
Prevenção contra SQL Injection

Também somos preocupados com segurança. Por isso, toda e qualquer


string usada como valor é passada pelo método Model::escape(),
escapando qualquer caracter que possa ser perigoso caso esteja em uma
consulta SQL. E não se preocupe com magic_quotes, o modelo já faz a
verificação e elimina barras quando necessário.

Caso você precise fazer consultas de maneira manual, ou precise


escapar qualquer string dentro da aplicação, basta usar essa mesma
função.

$this->Users->escape("String 'potencialmente' perigosa");


// Retorna "String \'potencialmente\' perigosa"

saveAll( array $data )

array $data Dados a serem salvos

Caso você precise salvar vários registros de uma só vez, o Spaghetti* lhe
dá a opção do método Model::saveAll(). Ele dispõe de todas as
funcionalidades de Model::save(), com exceção do parâmetro
recebido. Esse parâmetro deve ser um array com a seguinte estrutura:

Array
(
[0] => Array
(
[id] => 1
[name] => admin,
[password] => spaghettiphp
)
[1] => Array
(
[id] => 2
[name] => root,
[password] => root
)
[2] => Array
(
[id] => 3
[name] => user
[password] => 123456
)
)

Apagando Registros
delete( integer $id )

integer $id ID do registro a ser apagado

Model::delete() apaga apenas um registro com ID $id da tabela.


Como ele é limitado a apenas um registro, mesmo que existam vários
IDs iguais, apenas o primeiro será apagado.

deleteAll( mixed $conditions, mixed $order, integer


$limit )

mixed Array ou string contendo as condições para que


$conditions um registro seja apagado
Array ou string que define a ordenação dos
mixed $order
registros a serem apagados
integer $limit Limite de registros apagados

Model::deleteAll() faz a remoção de vários registros de uma única


vez, apagando registros que obedeçam às condições $conditions,
ordenados por $order e limitados por $limit.

Esse método é útil quando é necessário apagar vários registros, que não
obedeçam apenas a IDs, como usuários não aprovados ou mensagens de
spam.

$this->Users->deleteAll(array("approved" => false));

Métodos Personalizados
Os modelos de dados do Spaghetti* são poderosos o suficiente para
prover todas as funcionalidades básicas que você precisa para
desenvolver sua aplicação sem se preocupar com detalhes como
escrever SQL. Entretanto, você pode precisar de um pouco mais.

Não esqueça que as classes de modelo podem ser estendidas: basta


você adicionar métodos e propriedades! Qualquer função repetitiva
relacionada a banco de dados deve ser escrita aqui. Depois, você poderá
usá-la em qualquer controller que use esse modelo. DRY, tudo definido
em um lugar só!

class Posts extends AppModel {


public function findLastPosts() {
return $this->findAll(array("created <" => "curda
te()"), array("created" => "DESC"));
}
}

O método Posts::findLastPost(), depois de definido, pode ser


utilizado normalmente dentro de um controller.

$this->Posts->findLastPosts();
Relacionamentos entre
Models
Os relacionamentos entre modelos são uma das
características mais poderosas do Spaghetti*. Através deles, é
possível mapear as associações entre tabelas, tornando mais
fácil o trabalho com dados relacionados.

A necessidade de relacionamentos é suficientemente óbvia, e


naturalmente definida. Por exemplo, uma postagem em um blog
pertence a uma categoria, enquanto esse mesmo post possui vários
comentários. Através dessa definição, é possível acessar registros
relacionados entre si, retornando-os em apenas uma consulta.

Tipos de Relacionamentos
Até a versão atual, o Spaghetti* trabalha com 3 tipos diferentes de
associações: um para um, um para muitos e muitos para um.

Tipo de
Relacionamento Exemplos
Relacionamento
Um usuário possui um
hasOne Um para um
perfil
Um usuário possui vários
hasMany Um para muitos
posts
Um usuário pertence a um
belongsTo Muitos para um
grupo de usuários

Para que os relacionamentos funcionem corretamente é preciso que, em


uma das duas tabelas, exista um campo de chave estrangeira. Suponha
que exista um modelo Posts e um modelo Usuarios, e que vários posts
pertençam a um usuário. Nesse caso, é necessário que na tabela posts
exista um campo users_id para servir como chave estrangeira.

hasOne
Uma associação hasOne existe quando um registro pode ter apenas um
registro correspondente na tabela relacionada. Esse tipo de
relacionamento acontece, principalmente, entre tabelas de usuários e
tabelas de perfis.

Para definir o relacionamento um para um em um modelo, é preciso


definir a variável hasOne, com um array contendo todos os outros
modelos relacionados:

class Users extends AppModel {


public $hasOne = array("Profiles");
}

Nota: Para relacionamentos hasOne, uma das tabelas deve ter a chave
estrangeira correspondente. Em nosso caso, Profiles deveria possuir
o campo users_id.

Através desse relacionamento, é possível retornar todas as informações


de um usuário, com apenas uma chamada ao método
Users::findAll(), por exemplo.

$this->Users->findAll();

Através da consulta acima, é retornado um array com a seguinte


estrutura:

Array
(
[0] => Array
(
[id] => 1
[name] => admin,
[password] => spaghettiphp
[profiles] => Array
(
[id] => 1
[users_id] => 1
[realname] => Administrador do Site
)
)
[1] => Array
(
[id] => 2
[name] => root,
[password] => root
[profiles] => Array
(
[id] => 2
[users_id] => 2
[realname] => Super Usuário
)
)
[2] => Array
(
[id] => 3
[name] => user
[password] => 123456
[profiles] => Array
(
[id] => 3
[users_id] => 3
[realname] => Usuário Comum
)
)
)

hasMany

Um relacionamento um para muitos, assim como seu inverso, é um dos


mais comuns. Ele acontece quando um registro em determinada tabela
possui mais de um registro correspondente em outra tabela. Por
exemplo, um usuário pode ter vários posts, ou um post pode ter vários
comentários.

Para definir um relacionamento um para muitos, é preciso declarar a


variável hasMany no modelo de dados.

class Users extends AppModel {


public $hasMany = array("Posts");
}

Assim como em hasOne, também é possível acessar os registros


correspondentes através de métodos como Model::findAll().
Entretanto, por padrão o Spaghetti* retorna apenas os dados de
relacionamentos belongsTo e hasOne, para evitar a sobrecarga de seu
banco de dados. Para retornar registros de hasMany, é necessário passar
o parâmetro $recursion:

$this->Users->findAll(array(), null, null, 1);

O array retornado é apenas ligeiramente diferente do retornado por


hasOne:

Array
(
[0] => Array
(
[id] => 1
[name] => admin,
[password] => spaghettiphp
[posts] => Array
(
[0] => Array
(
[id] => 1
[users_id] => 1
[title] => Meu Primeiro Post
)
)
)
[1] => Array
(
[id] => 2
[name] => root,
[password] => root
[posts] => Array
(
[0] => Array
(
[id] => 2
[users_id] => 2
[title] => Esse é outro.
)
[1] => Array
(
[id] => 3
[users_id] => 2
[title] => Mais um post meu =P
)
)
)
)
Nota: nesse caso, a chave estrangeira deve estar presente apenas no
modelo relacionado, e não naquele em que se descreve o
relacionamento.

belongsTo

Relacionamentos muitos para um são exatamento o inverso de


relacionamentos um para muitos. Embora não seja necessário, acontece
em qualquer lado oposto de um relacionamento hasMany. Acontece
quando um post pertence a um usuário, ou quando um post pertence a
uma categoria.

Para descrever um relacionamento muitos para um, é necessário definir


a variável belongsTo no modelo desejado:

class Comments extends AppModel {


public $belongsTo = array("Posts");
}

Nota: em relacionamentos belongsTo, a chave estrangeira deve estar


presente apenas na tabela em que se descreve o relacionamento, e
não no modelo relacionado, justamente o contrário de
relacionamentos hasMany

Definindo Recursão
O Spaghetti* define uma recursão padrão para seus modelos, para que
você não precise se preocupar com sobrecarga em seu servidor de
banco de dados. Entretanto, muitas vezes é necessário definir uma
recursão maior, ou mesmo menor. É possível modificar essa recursão
padrão através da variável $recursion, definida na classe dos modelos
de dados.

class Users extends AppModel {


public $recursion = 1;
}

Caso esse número de recursões seja compartilhado entre todos os


modelos de sua aplicação, você pode criar o modelo AppModel em
app/models/app.php, e definir a mesma variável.

class AppModel extends Model {


// aqui estendemos Model em vez de AppModel!
public $recursion = 1;
}

O valor da recursão pode variar dependendo de sua necessidade. Os


valores possíves variam desde -1 até qualquer número positivo.

Recursão Dados retornados


-1 Nenhum registro relacionado é retornado.
São retornados apenas os registros relacionados
0
diretamente por hasOne e belongsTo
São retornados todos os registros relacionados
1
diretamente pelo modelo, incluindo hasMany
Além dos registros relacionados diretamente, retorna n
n>2
níveis de recursão

Não é necessário definir níveis de recursão maiores do que o necessário.


Isso pode diminuir a velocidade de sua aplicação, assim como causar
sobrecarga em seu servidor. Use com responsabilidade!

Definindo atributos para relacionamentos


O Spaghetti*, além de lhe prover várias convenções, também consegue
trabalhar muito bem sobre configuração. Você pode ter várias opções
para definir melhor seus relacionamentos.

Para definir as opções de relacionamentos, é necessário modificar um


pouco como os relacionamentos são definidos. Em vez de apenas um
array numerado, é necessário nomeá-lo, da seguinte maneira:
public $hasMany = array("assocName" => array("option" =>
"value"));

className determina o nome da classe do modelo relacionado.


Assim, é possível definir qualquer nome para a associação, sem que a
associação pare de funcionar.
foreignKey determina o nome da chave estrangeira. Como o
Spaghetti* ainda não conta com singularização/pluralização, você
pode definir manualmente um nome no singular, ou mesmo qualquer
outro nome, para a chave.
conditions é um array ou string de condições. Somente os registros
que obedeçam a essa condição serão adicionados à associação.
Condições Complexas
Arrays simples não dão conta de suas necessidades de SQL?
Tudo bem, o Spaghetti* ainda lhe dá mais poder na hora de
gerenciar suas consultas.

Com o Spaghetti*, a escrita de consultas SQL é tão rara que você


dificilmente se deparará com elas, a menos em casos bem específicos.
Com o uso de arrays, é possível criar condições facilmente, de leitura e
manutenção extremamente simples.

Basicamente, um array de condições contém pares de chaves e valores


definindo cada declaração. A condição abaixo, por exemplo, encontrará
registros em que title é igual a Hello World.

$conditions = array("title" => "Hello World");

É tão simples que você esquecerá que um dia precisou escrever SQL.
Mas isso não é tudo, é possível mais! Para adicionar outras declarações à
condição, basta adicionar outro item ao array.

$conditions = array("id" => "3", "title" => "Hello World");

Agora vamos a outros tipos de comparações. E se você estiver


procurando um registro no qual o título NÃO seja Hello World?

$conditions = array("title <>" => "Hello World");

Usando o operador SQL <>, o Spaghetti* encontrará registros em que o


título seja diferente de Hello World. Além desse operador, você pode
usar qualquer outro operador SQL válido, como >, < e LIKE, e o
Spaghetti* o reconhecerá e montará a consulta.
Para que o operador SQL seja reconhecido como tal, é necessário que
ele esteja separado do nome do campo por um espaço.

Além de comparações com um valor, também é possível usar


comparações com um conjunto de valores, como em uma consulta IN:

$conditions = array("title" => array("Primeiro Post",


"Segundo Post", "Terceiro Post"));

Esse mesmo princípio funciona com diferentes campos em uma mesma


condição OR:

$conditions = array(array("id" => 3, "title" => "Hello


World"));

Consultas BETWEEN também são criadas facilmente, basta adicionar o


operador BETWEEN juntamente com o nome do campo.

$conditions = array("id BETWEEN" => array(1, 15));

Embora o Spaghetti* cuide do trabalho sujo para você, algumas vezes é


necessário sujar as mãos e escrever SQL diretamente. Para isso, você só
precisa passar uma string como parâmetro.

$conditions = "id = 1 AND title = 'Hello World'";

Nota: em consultas manuais, os valores não são escapados pelo


Spaghetti*. Nunca confie em dados vindos do usuário, e sempre use
Model::escape() para fazer o escape de valores.
Controllers
É nos controllers onde tudo acontece. Aqui você começa a
programar de verdade, e a usar de todo o poder do
Spaghetti*.

Os controllers trabalham com toda a lógica da aplicação. Tarefas como o


processamento de dados vindos do usuário, a busca de registros no
banco de dados através dos models e a passagem dos dados para as
views.

Geralmente, controllers são associados a um único modelo. Para facilitar


seu trabalho, o Spaghetti* já associa por padrão seu controller com um
model de mesmo nome, sem necessitar de nenhuma configuração.

Criando Controllers
Para criarmos um controller, é preciso definir a classe
<nome>Controller, e salvá-la em app/controllers
/<nome>_controller.php. Também é necessário estender a classe
AppController, para que todos os métodos necessários sejam
herdados, e sua aplicação funcione corretamente.

class PostsController extends AppController { }

A partir de agora, a URL /posts já está disponível, embora retorne um


erro dizendo que a action ainda não existe. Precisamos resolver isso!

Criando Actions
Actions nada mais são do que métodos dentro de uma classe de
controller. Cada action corresponde a uma ação diferente de sua
aplicação. Ações podem ser o envio de um e-mail, o cadastro de um
usuário, a postagem de um artigo, entre qualquer outra coisa.
Para que sua aplicação funcione, é necessária a criação de actions e suas
respectivas views. Vamos criar uma action simples, para gerar uma lista
de posts:

class PostsController extends AppController {


public function index() {
$this->set("posts", $this->Posts->findAll());
}
}

A primeira coisa que devemos saber para podermos interagir entre


controllers e views é como se faz a passagem de variáveis. Para isso,
usa-se o método Controller::set, passando como parâmetros o
nome da variável e seu respectivo valor. Dentro da view, essa variável
estará disponível como uma variável local comum, acessível por $posts,
no nosso caso.

Você também pode notar que o modelo de dados já está disponível em


$this->Posts. Através desse objeto, é possível acessar todas as
propriedades do model Posts (que já deve existir em app/models
/posts.php).

A partir de agora, se a view já tiver sido criada em app/views/posts


/index.phtm, você já poderá ver o resultado em /posts. Como
nenhuma action é passada pela URL, o Spaghetti* supõe que esta seja
index. Qualquer outra action pode ser acessada através da estrutura
/controller/action.

Recebendo parâmetros
Diferente de páginas PHP comuns, os parâmetros no Spaghetti* não são
passados através de query strings, como ?id=1&page=2. Eles são
passados como parte da URL, com cada parâmetro gerando uma URL
diferente. O parâmetro mais usado é um número de identificação de um
registro, para que ele possa ser identificado no banco de dados. Quando
esse ID é passado como terceira parte da URL, ele já é identificado e
enviado para o controller.
Para que uma action possa receber parâmetros, é necessário definí-los
na função. Em uma ação de visualização de posts, pode-se fazer assim:

public function view($id = null) {


$this->set("post", $this->Posts->findById($id));
}

É recomendável que todo parâmetro tenha um valor padrão. Caso


contrário, se esse parâmetro não for passado, o PHP disparará um erro,
quebrando sua aplicação.

Além do ID, é possível passar qualquer outro parâmetro, bastando


adicionar mais partes na URL. Esse parâmetros são passados
sequencialmente para a action. Para receber os parâmetro passados pela
URL /posts/view/1/hello-world, nossa action precisaria mudar para:

public function view($id = null, $slug = "") {


$this->set("post", $this->Posts->find(array("id" =>
$id, "slug" => $slug)));
}

Nota: mesmo quando não estiver presente na URL, o ID é passado


como um valor nulo para a action. Caso você esteja usando
parâmetros textuais, é necessário definir o primeiro parâmetro
mesmo assim.

Recebendo Dados do Usuário


Além de receber parâmetros como ID, também é necessário receber os
dados enviados pelo usuário através do método POST. Assim que o
usuário envia uma requisição a partir de um formulário, todos os dados
de $_POST ficam disponíveis através da variável Controller::data.

Quando esses dados são recebidos, eles já estão prontos para serem
usados em qualquer consulta Model::save(), bastando passá-los como
parâmetro.
public function add() {
if(!empty($this->data)):
$this->Posts->save($this->data);
endif;
}

E lembre-se: a menos que seja definido um campo de nome id, o ID


passado como parâmetro na URL não é passado para
Controller::data, sendo necessário definí-lo manualmente.

public funcion edit($id = null) {


if(!empty($this->data)):
$this->data["id"] = $id;
$this->Posts->save($this->data);
endif;
}

Modelos, Helpers e Componentes


Por padrão, o Spaghetti* já vincula seu controller com um modelo de
mesmo nome. Entretanto, você pode precisar usar um modelo diferente
em determinados controllers, ou mesmo usar vários modelos dentro de
um mesmo controller. Para isso, o Spaghetti* usa a variável uses.

class UsersController extends AppController {


public $uses = array("Users", "Profiles");
}

Nota: Não é necessário incluir modelos relacionados caso eles não


sejam usados diretamente, o Spaghetti* já se encarrega disso!

Caso você não deseje utilizar modelo algum em seu controller, basta
definir essa variável como um array vazio:

class UsersController extends AppController {


public $uses = array();
}

Os componentes e helpers desejados também devem ser incluídos no


controller, através de suas respectivas variáveis components e helpers,
assim como na definição de modelos.

class UsersController extends AppController {


public $uses = array("Users", "Profiles");
public $components = array("Auth");
public $helpers = array("Html", "Form", "Date");
}

A menos que você deseje incluir outros helpers, não é necessário definir
Html e Form, já que eles são herdados de AppController.

Usando Layouts
Fazendo o uso de layouts, você economiza código HTML, gerando todo
o esqueleto da página apenas uma vez. Por padrão, o Spaghetti*
renderiza o layout default, que se encontra em app/layouts
/default.phtm. Entretanto, é possível escolher qualquer outro layout
disponível em sua aplicação através da variável layout.

class HomeController extends AppController {


public $layout = "home";
}

Muitas vezes um layout não é necessário, e você deseja que o Spaghetti*


não renderize nenhum. Nesse caso, é possível definir o valor da variável
como false e pronto!

Também usado geralmente nos layouts, o título da página também pode


ser definido pelo controller. Para tal, define-se a variável pageTitle,
com um texto qualquer que você queira ver no título.

class HomeController extends AppController {


public $pageTitle = "Minha Aplicação com Spaghetti*";
}

Essa variável também é recebida como uma variável local, tanto em


views quanto em layouts. Você pode imprimí-la onde desejar, seja na
tag <title>, em tags <h1>, ou onde mais se fizer necessário.

Redirecionamentos
Após uma ação, geralmente após editar ou apagar algum registro,
geralmente acontece um redirecionamento da aplicação. Os controllers
do Spaghetti* já herdam o método Controller::redirect() para esse
propósito. Basta definir a URL para a qual se deseja redirecionar.

$this->redirect("/home");

Como o redirecionamento é feito através de um header HTTP, também é


possível adicionar mais um header indicando o status da requisição.
Basta passar como segundo parâmetro o número do status, e o
Spaghetti* se encarrega de definir o header apropriado:

$this->redirect("/home", 404);
// gerando um erro 404 – página não encontrada

Além de redirecionamentos HTTP, o Spaghetti* também suporta que


você redirecione uma ação para outra do mesmo controller. Isso é feito
através do método Controller::setAction(), passando o nome da
ação como parâmetro. Qualquer outro parâmetro será passado
diretamente para a action definida.

Esse método é bastante útil para evitar a criação de várias views para
ações semelhantes, como adicionar e editar registros, por exemplo.

public function add() {


$this->setAction("edit");
}
public function edit($id = null) {
if(!empty($this->data)):
$this->data["id"] = $id;
$this->Posts->save($this->data);
endif;
}

Callbacks
Os callbacks são funções executadas em determinados momentos da
execução do Spaghetti*, como antes da execução de uma ação do
controller ou antes da renderização de uma view.

Callback Momento da execução


beforeFilter Antes da execução da action
Depois da execução da action, mas antes da
beforeRender
renderização da view
afterFilter Após execução da action e renderização da view

Esse callbacks podem ser usados para executar qualquer coisa que você
precise para seus controllers. Para definí-los, basta criar sua função
correspondente na classe de controller.

class HomeController extends AppController {


public function beforeFilter() {
$this->AuthComponent->check();
}
}

AppController
AppController é o controller base para todos os outros controllers na
aplicação. Isso significa que todo e qualquer método ou atributo que for
definido dentro dessa classe estará disponível para todos os outros
controllers da aplicação.

O uso dessa herança é muito útil no uso de callbacks, quando é


necessário que eles sejam executados em todas as partes da aplicação.
O componente AuthComponent, por exemplo requer que o método
check seja executado em todas as partes da aplicação.

Por padrão, o Spaghetti* usa o AppController da biblioteca padrão.


Entretanto, você pode criar o arquivo app/controllers
/app_controller.php, e então o Spaghetti* passará a usá-lo para
estender todos os outros controllers de sua aplicação.
Views
E chegamos à camada apresentacional do paradigma MVC: as
Views. Uma view é, geralmente, um arquivo HTML com pouca
ou nenhuma programação que serve para exibir na tela o
conteúdo que você desejar para uma action.

Enquanto dentro de um controller você desenvolve toda a lógica de


programação do seu sistema, utilizando modelos de acesso a dados e
outros componentes, em uma view você determina qual conteúdo será
exibido em uma determinada action.

No geral, pouco código PHP é escrito dentro de uma view, apenas as


estruturas básicas necessárias para manipular o conteúdo já mastigado
que você deve enviar a partir do controller. Existem quatro tipos básicos
de views:

1. Views estáticas
2. Views dinâmicas
3. Layouts
4. Elements

Views estáticas
As views estáticas são o tipo de view mais simples. Uma view estática
não recebe nenhum tipo de informação de um controller, logo, você
pode criar views estáticas sem precisar criar um controller. Por exemplo,
se você quiser criar uma página “Sobre Nós”, que em termos gerais não
demanda nenhum tipo de programação, apenas HTML simples, não faz
sentido criar um controller SobreNosController.

Então, para que você consiga acessar esta página através da URL
/sobre-nos/, por exemplo, você deve criar uma pasta sobre-nos no
diretório app/views/, e dentro dela criar um arquivo index.phtm.

Você pode, seguindo os mesmos princípios de funcionamento dos


controllers, criar sub-páginas estáticas. Se você quiser criar uma página
no endereço /sobre-nos/equipe, deve criar dentro daquela mesma
pasta app/views/sobre-nos o arquivo equipe.phtm.

Nota: o que faz uma view ser estática é o fato de não possuir código
PHP embutido. Porém, elas seguem exatamente as convenções das
views comuns, como a estrutura nos diretórios, extensão de arquivos,
etc.

Views dinâmicas
Ao contrário das views estáticas, as dinâmicas são aquelas onde você
utiliza código PHP em meio ao HTML. Desta maneira, torna-se
obrigatória a presença de um controller. Como descreve o padrão MVC,
a camada Controller é a responsável por manipular dados e pela lógica
de programação, apenas passando para a camada View o conteúdo já
digerido, pronto para ser apresentado na tela.

Por isso, em uma view dinâmica você irá, geralmente, receber apenas
variáveis enviadas pelo seu controller contendo strings ou arrays, e tudo
o que você precisará utilizar de código PHP dentro delas servirá para
imprimir o conteúdo destas variáveis na tela. Desta maneira, em sua
view você utiliza apenas estruturas básicas do PHP, como if, for e
foreach, apenas com esta lógica de apresentação da página.

Manipulando as variáveis enviadas pelo controller

Você receberá variáveis vindas do controller de maneira normal, como as


variáveis padrão do PHP. Se, por exemplo, você definir uma variável no
seu controller, conforme o exemplo:

$this->set("fruits", array("lemon","orange","apple","grape"));

Você então, em sua view, receberá uma variável $fruits, contendo


exatamente o mesmo array passado como segundo parâmetro do
método set do Controller. Se, por exemplo, quiser transformar este
array em uma lista não ordenada, pode utilizar a estrutura de controle
foreach, de acordo com o exemplo abaixo:

<ul>
<?php foreach($fruits as $fruit): ?>
<li><?php echo $fruit; ?></li>
<?php endforeach; ?>
</ul>

Layouts
Os layouts servem para englobar o conteúdo de uma view – geralmente
para adicionar a navegação geral do site, topo, menus e rodapé.

Elements
Os elements, por sua vez, são views que guardam trechos de código que
você utiliza com freqüência em várias partes diferentes de sua aplicação,
para que você possa utilizar o mesmo código várias vezes sem ter que
reescrevê-lo e sem copiar e colar.
Layouts
Os layouts fazem parte da camada de View da sua aplicação.
Geralmente compõem toda a parte apresentacional que
envolve uma view. Em um layout você geralmente inclui sua
marca, os menus de navegação, rodapé, entre outros.

Os layouts possuem um comportamento bastante semelhante ao das


outras views: são arquivos HTML mas, se necessário, você pode usar
estruturas simples de PHP, como laços de repetição. Contudo, eles não
possuem um controller-pai, pois são compartilhados geralmente entre
uma aplicação inteira.

O arquivo de layout padrão da sua aplicação Spaghetti* é o arquivo


app/layouts/default.phtm, mas você pode criar quantos layouts
diferentes você achar necessário.

Recebendo o conteúdo de uma view


Se você sobrescrever o layout padrão, montando uma estrutura
semelhante à seguinte, por exemplo:

<html>
<head>
<title>My Page</title>
</head>

<body>
<h1>Welcome to My Page</h1>
</body>
</html>

Você, no exemplo acima, terá uma página apenas com um cabeçalho


“Welcome to My Page”, porém perceberá que o conteúdo da view que
você pretendia exibir não aparece neste documento HTML. Acontece que
você precisa incluir uma variável convencionada chamada
$content_for_layout no local onde você deseja exibir o conteúdo de
sua view dentro deste layout, conforme o exemplo que segue:
<html>
<head>
<title>My Page</title>
</head>
<body>
<h1>Welcome to My Page</h1>
<?php echo $content_for_layout; ?>
</body>
</html>

No exemplo acima, portanto, além do cabeçalho “Welcome to My Page”,


o conteúdo da view solicitada será impresso logo em seguida.

Criando layouts e escolhendo qual utilizar


Se você possuir uma página de login em seu sistema, provavelmente
optará por escrever um layout próprio para esta página, livre dos
elementos de navegação presentes em todo o restante do sistema. Para
tal, você precisa criar um novo layout na pasta app/layouts/ com o
nome do arquivo que você desejar.

Então, deve entrar no controller onde deseja alterar o layout, e incluir


em seu controller a seguinte atribuição:

public $layout = "login";

No exemplo acima, quando alguma action do controller onde a variável


$layout foi atribuída for chamada, o Spaghetti* procurará pelo arquivo
login.phtm na pasta app/layouts/. Você pode também definir um
layout específico para uma action, sem precisar afetar todo as outras
actions de um mesmo controller. Para tal, adicione a seguinte atribuição
dentro da __action desejada:

$this->layout = "login";

Neste caso, apenas a action onde a atribuição acima foi feita é que será
afetada pelo layout escolhido, neste caso app/layouts/login.phtm.
Alterando o layout padrão da aplicação

Conforme dito anteriormente, o layout padrão da sua aplicação é


app/layouts/default.phtm. Porém, caso prefira utilizar outro arquivo,
pode alterar o layout padrão definindo-o no AppController de sua
aplicação, que encontra-se em app/controllers
/app_controller.php, adicionando a seguinte atribuição à classe
AppController:

<?php
class AppController extends Controller {
public $layout = "login";
}
?>

Neste caso, a aplicação toda será afetada e o layout login.phtm.

Usando helpers nos layouts


Você pode utilizar todos os helpers disponíveis para suas views em seus
layouts, contanto que estes helpers tenham sido definidos dentro do
controller atual. Para evitar que algum helper não seja incluído por
acidente, é uma boa dica carregar os helpers de sua aplicação no
AppController, ao invés de carregá-lo em cada controller que criar.

Definindo um título para a página


Há uma maneira de definir o conteúdo da tag <title> de maneira a não
criar código com gambiarras. De modo semelhante à variável
$content_for_layout, há uma variável chamada $this->pageTitle,
definida dentro de um controller ou action (à sua escolha), onde você
pode especificar o conteúdo da tag <title> que será exibido em
qualquer lugar do documento HTML.

Para exibir o conteúdo da variável $this->pageTitle em seu layout,


escreva seu conteúdo dentro da tag <title>, como no exemplo:
<title><?php echo $this->pageTitle; ?></title>

E para definir o conteúdo da variável $this->pageTitle, faça uma


atribuição normal dentro do controller ou action desejado, como nos
respectivos exemplos que seguem:

public $pageTitle = "Page Title Goes Here";

$this->pageTitle = "Page Title Goes Here";


Elements
Por muitas vezes você ocupa pequenos trechos de código em
várias páginas, porém estes trechos não fazem parte de um
layout. Não se repita, utilize elements. Elementos são views
que servem apenas nestas ocasiões.

Quer um exemplo? Você pode ter um formulário de login ao topo da


página e um no meio do conteúdo. Vai copiar e colar código? E quando
for necessário fazer manutenção? É trabalho dobrado para você. Se você
criar um element, tudo o que você precisará fazer é escrever o trecho de
código uma única vez, e então chamá-lo sempre que necessário.

Criando um element
A criação é muito simples. Crie um arquivo com o nome desejado para
seu element, com a extensão .phtm, logo na pasta app/views/, sem
colocar em nenhuma subpasta. No início do nome do arquivo deve
constar um caracter underscore (_), para sinalizar que aquele arquivo é
um element. Veja o exemplo abaixo:

app/views/_formulario_de_login.phtm

Quando você quiser incluir o conteúdo deste element em alguma outra


view, seja ela estática, dinâmica ou um layout, basta utilizar o método
$this->element(), passando como parâmetro o nome do elemento sem o
underscore nem a extensão do arquivo:

<?php echo $this->element("formulario_de_login"); ?>

E pronto. O conteúdo do elemento será renderizado tantas vezes quanto


for chamado, e nos lugares onde for chamado.

Passando parâmetros para elements


Hora ou outra você pode precisar passar conteúdo dinâmico para um
element. Por exemplo, você pode criar um element para armazenar um
elemento <select> com a lista dos estados nacionais. Este elemento de
formulário seria utilizado em diferentes formulários no seu site.

Porém, você pode querer passar para este campo de formulário qual é o
estado que deve estar selecionado, baseado no estado onde o usuário
logado mora. Sem elements, além de manter diversos formulários por
todo o site, você teria que reescrever código e a cada manutenção, bom,
você já sabe.

Para passar variáveis para um element, ao usar o método


$this->element() você pode passar como segundo parâmetro um
array, onde a chave de um item é o nome da variável e seu valor é o
conteúdo da variável, como no exemplo:

$options = array(
"selectedState" => "SP"
);
echo $this->element("formulario_dos_estados", $options);

E então, dentro do element você possui condições de manipular esta


variável, chamando-a pelo nome.

<?php echo $selectedState; ?>

Elements são um instrumento bastante interessante de manter o código


reaproveitável e de mais fácil manutenção. Use sem moderação ;D
Helpers
Helpers são classes semelhante aos componentes, porém são
exclusivas para as views e para a lógica presentacional
compartilhada entre views, layouts e elements. Nestas classes
você encontra funções que tornam o seu desenvolvimento
client-side mais rápido e fácil.

Dois helpers vêm habilitados por padrão na instalação do Spaghetti*: um


para HTML e outro para formulários.

Utilizando os helpers
Conforme dito acima, você só poderá usar as funções de um helper
dentro de uma view, layout ou element. Para mais informações sobre
como utilizar cada helper, consulte as documentações específicas ao
lado.

Criando seu próprio helper


Para criar um helper, crie um arquivo nome_do_helper_helper.php na
pasta app/helpers/. Por exemplo, se fôssemos criar um helper
chamado Number, ele seria o arquivo app/helpers
/number_helper.php, e dentro dele haveria a classe NumberHelper que
estende a classe Helper.

Como os helpers são específicos para as views, você não conseguirá


ter acesso a modelos de dados de dentro deles.

Carregando um helper

Você precisa então chamar este helper no controller onde você pretende
usá-lo. Caso queira usar um helper com toda a aplicação, carregue-o
dentro do AppController, localizado em app/controllers
/app_controller.php, adicionando a seguinte variável de instância à
classe:

public $helpers = array("Number");

Continuando no exemplo, neste caso carregaríamos no controller o


helper Number. Porém é importante ressaltar que, definindo o array com
apenas Number, os outro helpers embutidos no Spaghetti* não serão
mais carregados, pois você está sobrescrendo a chamada padrão. Para
continuar a carregar os helpers padrão do Spaghetti, adicione a variável
de classe desta maneira:

public $helpers = array("Html", "Form", "Number");

Agora seu helper já está pronto para ser usado nas views do seu
controller (ou da aplicação inteira, caso tenha incluído o helper no
AppController).

Usando o helper na view

Se o seu helper se chamar Number, logo ele estará acessível em uma


view através da variável $number, como no exemplo abaixo:

<h1>My Blog</h1>
<?php echo $number->ceil(2.0324); ?>

A chamada acima procurará pelo helper Number e pelo seu método


ceil(), que pode ser escrito assim:

<?php class NumberHelper extends Helper {


public function ceil($number = null) {
$numeroArredondado = ceil($number);
$this->output($numeroArredondado);
}
} ?>
Repare que para passar a saída da função você utiliza o método
$this->output() passando como parâmetro o conteúdo que você
deseja retornar.
HTML Helper
O helper HTML agiliza a criação de alguns dos elementos que
mais tomam tempo, como os chamados para CSS e JavaScript,
criação de links a e inserção de imagens img.

O helper HTML vem carregado por padrão na sua aplicação Spaghetti*, e


portanto é acessível de qualquer view utilizando a variável $html.

Inserindo links para outras páginas


$html->link( string $value, string $url, array $attributes
)

string $value String contendo o conteúdo do link


string $url String contendo a URL do link
array $attributes Array contendo atributos do elemento a

Para gerar links internos basta escrever a URL iniciando pela barra (/),
passando esta URL normalmente como segundo parâmetro do método
$html->link(). O helper gerará o endereço completo para você.

<?php echo $html->link("Adicionar Recado", "/recados/


adicionar"); ?>

// Gerará o seguinte:
// <a href="/recados/adicionar">Recados</a>

Criando links para páginas externas

Para gerar links externos basta escrever a URL normalmente como


segundo parâmetro do método $html->link():

<?php echo $html->link("Google", "http://www.google.com


.br"); ?>

// Gerará o seguinte:
// <a href="http://www.google.com.br">Google</a>

Passando atributos para o elemento a

Você pode definir todos os atributos disponíveis passando-os como


itens de array no terceiro parâmetro do método $html->link():

<?php echo $html->link("Google", "http://www.google.com


.br", array("class"=>"google-link")); ?>

// Gerará o seguinte:
// <a href="http://www.google.com.br" class="google-link"
>Google</a>

Criando links em imagens

Além disso, se quiser gerar um link em uma imagem, pode também


utilizar o método $html->image() do helper HTML para gerar a tag
img, conforme o exemplo abaixo:

<?php echo $html->link( $html->image("btadicionar.gif",


"Adicionar Recado") , "/recados/adicionar"); ?>

// Gerará o seguinte:
// <a href="/recados/adicionar"><img src=/images/botao_
adicionar.gif" alt="Adicionar Recado" /></a>

Criando links com URLs completas

Por fim, caso precise gerar URL’s completas em seus links, defina o
quarto parâmetro do método $html->link() como true.

<?php echo $html->link("Apagar Página", "/paginas/apagar"


, array(), true); ?>

// Gerará o seguinte:
// <a href="http://suaapp.com/pagina/apagar">Apagar</a>

Inserindo imagens na sua página


$html->image( string $url, string $alt, array $attributes )
string $url String contendo a URL da imagem
String contendo o texto do atributo alt (conteúdo
string $alt
alternativo) da imagem
array
Array contendo atributos do elemento img
$attributes

O exemplo abaixo mostra como inserir uma imagem no documento


HTML.

<?php echo $html->image("natal/foto01.jpg", "Foto de


Natal"); ?>

// Gerará o seguinte:
// <img src="http://www.suaaplicacao.com/images/natal/
foto01.jpg" alt="Foto de Natal" />

Nota: O diretório base das imagens é app/webroot/images/. Por


exemplo, se a imagem logo.gif estiver logo na raiz da pasta
app/webroot/images/, você deve passar como URL da imagem
apenas logo.gif, pois o helper se encarregará de completar o
endereço automaticamente.

Inserindo imagens hospedadas externamente

Para inserir imagens hospedadas em endereços externos, tudo o que


você precisa fazer é informar a URL completa da imagem, como mostra
o exemplo abaixo.

<?php echo $html->image("http://google.com/coruja.gif",


"Coruja"); ?>

// Gerará o seguinte:
// <img src="http://google.com/coruja.gif" alt="Coruja" />

Passando mais atributos para a imagem

Se precisar inserir mais atributos HTML em sua imagem, passe como


terceiro parâmetro do método $html->image() um array contendo os
atributos desejados, como no exemplo abaixo.
<?php echo $html->image("/papagaio.gif", "Papagaio",
array("class"=>"foto")); ?>

// Gerará o seguinte:
// <img src="/images/papagaio.gif" alt="Papagaio" class=
"foto" />

Insira CSS em sua página


$html->stylesheet( mixed $url, array $attributes,
boolean $full )

String contendo a URL do arquivo CSS ou Array,


mixed $url
caso sejam várias folhas de estilo
array
Array contendo atributos do elemento style
$attributes
boolean $full Se true, passa a URL inteira como atributo href

O seguinte exemplo gerará um elemento style chamando um arquivo


CSS.

<?php echo $html->stylesheet("default.css"); ?>

// Gerará o seguinte:
// <link href="/styles/default.css" rel="stylesheet"
type="text/css" />

Nota: O diretório base dos arquivos CSS é app/webroot/styles/,


então quando você utilizar o helper HTML para incluir seus arquivos
CSS, a URL da folha de estilos deve ser relativa a este diretório.

Inserindo estilos hospedados em um servidor externo

Para incluir um CSS hospedado em outro servidor, apenas informe a URL


completa, como no exemplo que segue:

<?php echo $html->stylesheet("http://www.google.com/


default.css"); ?>

// Gerará o seguinte:
// <link href="http://www.google.com/default.css" rel=
"stylesheet" type="text/css" />

Inserindo múltiplos estilos de uma vez

Seguindo os princípios de DRY, passar uma nova instrução nova para


cada folha de estilo a ser inserida é desperdício de tempo. Por isso, se
você precisar incluir várias folhas de estilo, pode passar um array de
URLs como primeiro parâmetro do método $html->stylesheet(),
como no exemplo abaixo:

<?php echo $html->stylesheet(array("default.css",


"home.css" ,"form.css")); ?>

// Gerará o seguinte:
// <link href="/styles/default.css" rel="stylesheet"
type="text/css" />

// <link href="/styles/home.css" rel="stylesheet" type=


"text/css" />

// <link href="/styles/form.css" rel="stylesheet" type=


"text/css" />

Passando atributos para a tag style

Se você precisar passar parâmetros para a tag style, pode fazê-lo


passando um array de argumentos como segundo parâmetro do método
$html->stylesheet(), seguindo o exemplo abaixo:

<?php echo $html->stylesheet("default.css", array(


"media"=>"handheld")); ?>

// Gerará o seguinte:
// <link href="/styles/default.css" rel="stylesheet"
type="text/css" media="handheld" />

Chamando folhas de estilo com URLs completas

Por fim, caso precise gerar URL’s completas em suas tags style, defina
o terceiro parâmetro do método $html->stylesheet() como true.
<?php echo $html->stylesheet("default.css", array(), true
); ?>

// Gerará o seguinte:
// <link href="http://suaapp.com/styles/default.css"
rel="stylesheet" type="text/css" />

Inserindo arquivos JavaScript na página


$html->script(mixed $src, array $attributes, array
$full )

String contendo a URL do arquivo Javascript ou


mixed $url
Array, caso sejam vários arquivos
array
Array contendo atributos do elemento script
$attributes
boolean $full Se true, passa a URL inteira como atributo src

O seguinte trecho de código gerará um elemento script chamando um


arquivo .js.

<?php echo $html->script("default.js"); ?>

// Gerará o seguinte:
// <script src="/scripts/default.js"
type="text/javascript"></script>

Nota: O diretório base dos arquivos JavaScript é app/webroot


/scripts/, então quando você utilizar o helper HTML para incluir
seus arquivos JavaScript, a URL do arquivo deve ser relativa a este
diretório.

Inserindo arquivos de script hospedados em um servidor externo

Para incluir um arquivo JavaScript hospedado em outro servidor, apenas


informe a URL completa, como no exemplo que segue:
<?php echo $html->script("http://www.google.com/defa
ult.js"); ?>

// Gerará o seguinte:
// <script src="http://www.google.com/default.js"
type="text/javascript"></script>

Inserindo múltiplos arquivos JavaScript de uma vez

Seguindo os princípios de DRY, passar uma nova instrução nova para


cada arquivo de script a ser inserido é desperdício de tempo. Por isso, se
você precisar incluir vários arquivosp, pode passar um array de URLs
como primeiro parâmetro do método $html->script() como no
exemplo abaixo:

<?php echo $html->script(array("default.js",


"jquery.js")); ?>

// Gerará o seguinte:
// <script src="/scripts/default.js"
type="text/javascript"> </script>
// <script src="/scripts/jquery.js"
type="text/javascript"> </script>

Passando atributos para a tag script

Se você precisar passar parâmetros para a tag script, pode fazê-lo


passando um array de argumentos como segundo parâmetro do método
$html->script( seguindo o exemplo abaixo:

<?php echo $html->script("default.js", array("defer"


=> "defer")); ?>

// Gerará o seguinte:
// <script src="/scripts/default.js"
type="text/javascript" defer="defer"></script>

Chamando arquivos de script com URLs completas

Por fim, caso precise gerar URL’s completas em suas tags script, defina
o terceiro parâmetro do método $html->script()como truH
<?php echo $html->script("default.js", null, true)
; ?>

// Gerará o seguinte:
// <script src="http://suaapp.com/scripts/default.js"
type="text/javascript" />
Form Helper
O Form Helper é o helper que torna a criação de formulários
em HTML um pouco menos trabalhosa. Embora ainda esteja
em um estágio inicial de desenvolvimento, já provém as
funcionalidades básicas para agilizar a escrita de formulários.

O helper Form já vem instalado e habilitado por padrão em sua


instalação do Spaghetti*. Portanto, a partir de qualquer view, pode
acessar os métodos disponíveis através da variável $form.

Criando um formulário novo


$form->create( string $action, array $attributes )

String opcional indicando a URL de ação do


string $action
formulário
array
Array opcional de atributos da tag form
$attributes

Se você utilizar o método $form->create() sem passar qualquer


parâmetro, a tag padrão será criada, apontando a ação para a URL atual.

<?php echo $form->create(); ?>

// Gerará o seguinte:
// <form action="http://suaapp.com/url_atual_da_pagina"
method="post">

Especificando uma URL de ação para o formulário

Para especificar a URL para onde o formulário deverá ser enviado, você
precisa apenas passar esta URL como primeiro parâmetro do método
$form->create().

<?php echo $form->create("http://suaapp.com/enviar"); ?>


// Gerará o seguinte:
// <form action="http://suaapp.com/enviar" method="post">

Passando outros atributos para a tag form

Caso você ainda precise passar outros atributos para a tag de abertura
do formulário, como por exemplo alterar o método de envio de POST
para GET, pode fazê-lo passando um array de argumentos como
segundo parâmetro do método $form->create().

<?php echo $form->create(null, array("method"=>"get")); ?>

// Gerará o seguinte:
// <form action="http://suaapp.com/url_atual_da_pagina"
method="get">

Adicionando campos ao seu formulário


Você pode criar todas as tags de um formulário utilizando o método
$form->input(), seguindo a seqüência de parâmetros abaixo. Você
pode passar, no parâmetro $options, um array contendo todos os
atributos disponíveis para o elemento em questão.

$form->input( string $name, string $value, array


$options )

Nome do campo de formulário que você deseja


string $name
criar
string $value Valor opcional do campo de formulário
array
Array de opções e atributos do campo
$options

Criando campos de texto (text)

<?php echo $form->input("nome", "João da Silva", array(


"type"=>"text", "id"=>"seuNome")); ?>

// Gerará o seguinte:
// <input type="text" name="nome" value="João da Silva"
id="seuNome" />

Criando caixas de texto (textarea)

<?php echo $form->input("biografia", "Nasci em São Paulo."


, array("type"=>"textarea", "id"=>"suaBiografia")); ?>

// Gerará o seguinte:
// <textarea name="nome" id="suaBiografia">Nasci em
São Paulo.</ textarea>

Criando campos de senha (password)

<?php echo $form->input("senha", null, array("type"=>


"password", "id"=>"suaSenha")); ?>

// Gerará o seguinte:
// <input type="password" name="senha" id="suaSenha" />

Criando caixas de seleção (select)

<?php echo $form->input("estado", "rj", array("type"=>


"select", "options" => array("rj"=>"Rio de Janeiro",
"sp" => "São Paulo") )); ?>

// Gerará o seguinte:
// <select name="estado">
// <option name="rj" selected="selected">Rio</option>
// <option name="sp">São Paulo</option>
// </select>

Nota: Neste caso, você passa como segundo parâmetro do método


$form->input() a chave do campo que deve estar selecionado por
padrão dentro do select.

Criando campos de arquivo (file)

<?php echo $form->input("foto", null, array("type"=>"file")


); ?>

// Gerará o seguinte:
// <input type="file" name="foto" />
Nota: Sempre que você for fazer upload de arquivos, deve acrescentar
à tag de abertura do formulário o atributo enctype com o valor
multipart/form-data.

Finalizando e enviando o formulário


Você geralmente coloca seu botão de envio de formulários logo antes do
término do mesmo. Por esse motivo, você pode usar o mesmo método
de encerramento do formulário para gerar – de maneira fácil – o botão
de envio.

$form->close( string $buttonValue, array $attributes )

string Nome do botão de envio, caso você queira


$buttonValue utilizá-lo
array $attributes Array de atributos do botão de envio

Passando apenas o método, sem qualquer parâmetro, você apenas


encerra o formulário com a tag </code>.

<?php echo $form->close(); ?>

// Gerará o seguinte:
// </form>

Agora, passando também um parâmetro, você gerará um input button


antes do encerramento do formulário.

<?php echo $form->close("Enviar"); ?>

// Gerará o seguinte:
// <input type="submit" name="Enviar" />
// </form>

Se você ainda precisar de outros atributos em seu botão, pode passar


como segundo parâmetro do método $form->close() um array
contendo estes atributos.
<?php echo $form->close("Enviar", array(
"id"=>"submitButton")); ?>

// Gerará o seguinte:
// <input type="submit" name="Enviar" id="submitButton" />
// </form>

Criando labels para os campos


É importante rotular seus campos, e usando o elemento label você
torna esta rotulagem ainda mais semântica. Você não precisa chamar
métodos adicionais para rotular um campo, apenas deve incluir um
atributo no array de atributos do elemento que você deseja rotular.

<?php echo $form->input("company", null, array(


"type"=>"text", "id"=>"myCompany",
"label"=>"Sua Empresa")); ?>

// Gerará o seguinte:
// <label for="myCompany">Sua Empresa
// <input type="text" name="company" id="myCompany" />
// </label>
Components
Você já viu essa história antes: você começa um projeto,
programa uma solução, começa um novo projeto, programa
novamente a mesma solução. Components são extensões
auto-suficientes, plug and play, para que você não se
incomode mais com tarefas repetitivas.

Os exemplos mais clássicos incluem envio de e-mails, upload de


arquivos e autenticação de usuários. Estamos sempre desenvolvendo
novos componentes para nossos próprios problemas, e então
compartilhamos eles aqui.

Instalando um componente
Não há segredos quanto a instalação de um novo componente em sua
aplicação. Quando você baixa um componente, extraia o arquivo ZIP e
copie o arquivo PHP para a pasta app/components/. E é isso. Já está
instalado.

Um componente, entretanto, embora esteja instalado não é ativado por


padrão. Isso quer dizer que você precisa informar quando deseja usar
um componente dentro de um controlador. Para tal, adicione a variável
de instância em seu controller conforme o exemplo abaixo:

public $components = array("NomeDoComponente");

Você pode ainda carregar vários componentes dentro de um controller


passando vários itens dentro do array:

public $components = array("NomeDoComponente1",


"Nome do Componente2");

Utilizando o componente
Vamos supor que você tenha carregado um componente chamado
Upload em seu controlador Fotos. Para que você tenha acesso às
funcionalidades dentro do controller Fotos, a instância do objeto Upload
fica gravada em $this->UploadComponent.

Por exemplo, caso você precise utilizar o método upload() deste


componente, você o faria dentro de uma action da seguinte maneira:

$this->UploadComponent->upload()

Nota: Lembre-se sempre que cada componente possui seus próprios


métodos e próprio funcionamento. O exemplo acima meramente
ilustra como carregar, instanciar e utilizar os métodos de um
componente.

Escrevendo seus próprios componentes


Um componente basicamente é composto por uma classe, chamada de
NomeDoComponenteComponent, que estende a classe Component. O
arquivo deve ser chamado, neste exemplo,
nome_do_componente_component.php, e deve estar na pasta de
componentes da sua aplicação em app/components/.

Um objeto da classe do seu componente será instanciado


automaticamente sempre que um controller solicitar. Por tanto, pelo fato
de se tratar de um processo automático, não há como passar
parâmetros para o construtor de sua classe. Isso significa que, se você
precisar atribuir valores às variáveis de instância, deve fazê-lo dentro do
controlador, conforme o exemplo:

$person = $this->PersonComponent;
$person->name = "Roberto";
$person->age = 32;
AuthComponent
A autenticação de usuários é algo comum a maioria das
aplicações hoje em dia. Pensando nisso, o Spaghetti* já traz o
componente AuthComponent em seu núcleo, pronto para ser
usado!

O uso do AuthComponent é extremamente simples, e sua configuração


requer apenas algumas linhas. Em poucos minutos você já tem um
sistema de autenticação de usuários simples funcionando.

Para usar o AuthComponent, primeiro é preciso ativá-lo nos controllers


em que você deseja usá-lo. Como geralmente a autenticação se aplica a
vários controllers dentro da aplicação, é recomendável definí-lo
diretamente no AppController.

class AppController extends Controller {


public $components = array("Auth");
}

Assim que o componente é ativado, ele se torna disponível dentro do


controller através de $this->AuthComponent. Assim, podemos começar
a utilizar seus métodos.

Criando o modelo de usuários


O AuthComponent já espera que você possua um modelo Users, e sua
respectiva tabela com, no mínimo, os campos username e password.
Caso seja necessário mudar essas opções, você precisa definir isso
dentro do controller, no callback beforeFilter().

class AppController extends Controller {


public $components = array("Auth");
public function beforeFilter() {
// definindo o modelo de usuários
$this->AuthComponent->userModel = "AppUsers";
// definindo os campos de nome de usuário e senha
$this->AuthComponent->fields = array(
"username" => "name",
"password" => "passphrase"
);
}
}

Ações de Login e Logout


Para que possamos fazer a autenticação do usuário, é necessário
criarmos as actions para login e logout. AuthComponent, por padrão,
redireciona o usuário para /users/login e /users/logout. Então, em
um controller Users, devemos criar essas duas ações.

class UsersController extends AppController {


public function login() {
$this->AuthComponent->login();
}
public function logout() {
$this->AuthComponent->logout();
}
}

Assim que essas duas ações são chamadas, é necessário disparar os


métodos da classe AuthComponent, login() e logout(). São essas
duas funções que farão a verificação, autenticação e desautenticação do
usuário. Embora essas funções cuidem da parte difícil, você ainda
precisa criar a view de login.

<?php echo $form->create(); ?>


<?php echo $form->input("username");
// deve ser o mesmo nome definido em
// AuthComponent::fields["username"] ?>
<?php echo $form->input("password");
// deve ser o mesmo nome definido em
// AuthComponent::fields["password"] ?>
<?php echo $form->close("Entrar"); ?>

Checando o usuário e permitindo acesso


Para que possamos checar se o usuário está autenticado, precisamos
adicionar uma chamada ao método AuthComponent::check() no
callback beforeFilter() do controller. Esse método checa se o usuário
está autenticado, e faz o redirecionamento para a tela de login, quando
necessário.

public function beforeFilter() {


$this->AuthComponent->check();
}

Mesmo assim, o usuário ainda tem acesso a todos os recursos da


aplicação, por padrão o componente permite acesso a toda a aplicação.
As permissões podem ser definidas aos níveis de prefixo, controller e
action, e são definidas através dos métodos allow e deny.

public function beforeFilter() {


$this->AuthComponent->check();
$this->AuthComponent->deny("*");
// nega acesso a toda página que não possuir um prefixo
$this->AuthComponent->allow(array("controller" =>
"users", "action" => "register"));
$this->AuthComponent->allow(array("prefix" => "public"));
}

Às vezes, também é preciso verificar se um usuário está aprovado para


efetuar login, ou se ele pertence a determinado grupo de usuários.
Nesse caso, usa-se o atributo userScope, que provê condições
adicionais para a verificação.

public function beforeFilter() {


$this->AuthComponent->check();
$this->AuthComponent->deny("*");
$this->AuthComponent->userScope = array("approved"
=> true, "group <>" => "banned");
}

Recuperando dados do usuário


Dentro da aplicação, também pode se fazer necessária a recuperação de
dados do usuário, para poder usá-los na identificação de registros.
Sempre que for necessária a utilização de alguma informação do usuário
na aplicação, usa-se o método AuthComponent::user(), passando
como parâmetro o campo que se deseja retornar.

$this->AuthComponent->user("id"); // retornará o id do usuário

Encriptando Senhas
Não é seguro, e nem considerado uma boa prática, manter as senhas
dos usuários sem nenhum tipo de criptografia. O AuthComponent usa
hashes MD5, que são um tipo de criptografia de apenas uma via, para
armazenar senhas. Isso significa que uma vez que uma senha for
criptografada, não há maneira de convertê-la de volta, apenas criar uma
nova senha. Assim, toda senha em seu banco de dados deve seguir esse
padrão.

Para que você não precise usar diretamente a função md5(), o


AuthComponent já possui o método hashPasswords(). Ele recebe um
parâmetro provindo de Controller::data, e criptografa o campo
definido como campo de senha por
AuthComponent->fields["password"].

Variáveis para personalização


Caso alguma das configurações padrão do AuthComponent seja
diferente das suas necessidades, é possível personalizá-lo de forma que
lhe atenda melhor. As variáveis configuráveis são:

Variável Função
URL para a qual o usuário será redirecionado quando
loginAction
não estiver autenticado
URL para qual o usuário será redirecionado quando
loginRedirect
efetuar login
URL para a qual o usuário será redirecionado quando
logoutRedirect
efetuar logout
Pois é, acredite se quiser: você chegou ao fim

Próximas do livro. Estamos felizes pelo seu interesse em

etapas aprender mais sobre o Spaghetti* e sobre como


tornar seu trabalho mais divertido e produtivo.
Neste ponto você deve estar pronto para fazer
sua primeira aplicação, fazendo o uso de todos
os conceitos e conhecimentos adquiridos
durante a leitura deste livro.

Acima de tudo, independente de qual


framework ou linguagem você vá utilizar daqui
em diante, parabenizamos você por optar
desenvolver Web do jeito certo. Agradecemos
pela oportunidade que você nos deu de
conhecer o nosso trabalho, e ficaremos ainda
mais contentes se você utilizar o Spaghetti* em
algum projeto.

A partir de agora, se você tiver interesse, pode


continuar acompanhando a evolução e as
novidades que virão através do site,
http://spaghettiphp.org. Lá você sempre
encontrará a documentação mais atual,
screencasts, tutoriais e o Trac - onde está o
repositório de versões de todo o código escrito
para o projeto.

Saúde e prosperidade para você e sua equipe, e


divirta-se com Spaghetti*!

Publicado em 1 de janeiro de 2009


E-mail de contato:
spaghetti@spaghettiphp.org

Este documento está licenciado sobre a Licença Creative Atribuição-Compartilhamento pela mesma
Licença 2.5 Brasil Commons, disponível em http://creativecommons.org/licenses/by-sa/2.5/br
/legalcode.

Anda mungkin juga menyukai