Você está na página 1de 69
Introdução ao desenvolvimento com Spaghetti* Aprenda a desenvolver com produtividade e diversão por Julio Gre
Introdução ao
desenvolvimento
com Spaghetti*
Aprenda a desenvolver com
produtividade e diversão
por Julio Gre e Rafael Marin

Olá!

Seja bem vindo ao mundo do desenvolvimento Web 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 loso a. Uma

loso a 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 su ciente, 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 ca 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 e ciente.

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 signi ca 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 con guração? Não nesse framework. Qualquer aplicação do Spaghetti* já está pronta para ser desenvolvida em questão de segundos!

Con gurar o Spaghetti* é realmente muito fácil. Embora algumas outras con gurações sejam possíveis, a única coisa que você necessita para ter uma aplicação rodando é de nir as con gurações de seu banco de dados.

Con gurando o banco de dados

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

$database = array( "development" => array( "host" => "localhost", "user" => "username", "password" => "password", "database" => "spaghetti", "pre x" => ""

);

)

O Spaghetti* suporta con gurações diferentes para cada ambiente de desenvolvimento. No exemplo acima, de nimos o ambiente development , mas também podemos de nir quantos mais forem necessários. Isso evita que você sobrescreva con gurações, facilitando o deploy da aplicação.

Escolhendo o Ambiente

Para escolher o ambiente que você deseja usar, basta alterar a con guração environment no arquivo app/con g/settings.php :

Con g::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 con guraçã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 modi cações nessa estrutura. Esse é o propósito do arquivo app/con g/routes.php .

Rotas Padrão

Quando você abrir o arquivo de con guração de rotas, você já encontrará uma chamada ao método Mapper::connect() , de nindo 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 é especi cado na URL. Caso contrário, será chamada a classe Controller , que é apenas uma classe base, e não um

controller propriamente dito.

Denindo novas rotas

A de nição de novas rotas modi cará a resposta de sua aplicação de

acordo com a URL acessada. As rotas devem ser de nidas no mesmo arquivo app/con g/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/de nindo-novas-rotas aponta

para /posts/view/de nindo-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 corresponde a qualquer caracter, incluindo barras

:num corresponde a qualquer número, mas não inclui barras 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 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.

Denindo pre xos

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 pre xos, através do método Mapper::pre x() :

Mapper::pre x("admin");

Quando um prexo é de nido, 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: Pre xos também estão sujeitos a ação de rotas, ou seja, uma rota pode redirecionar um pre xo e causar problemas em sua aplicação.

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

Mapper::pre x("admin", "user");

Através da criação de múltiplos pre xos você pode segmentar sua aplicação, criando várias áreas distintas, com uma estrutura exível e bem de nida.

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í co, 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 de niçã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 de nir 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 busca

$conditions

mixed $order

Array ou string que de ne a ordenação dos registros

string $limit

Limite de registros a serem recuperados

integer

Número de recursões para tabelas relacionadas

$recursion

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

condição $conditions especi cada, 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-> ndAll($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:

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
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 busca

$conditions

mixed $order

Array ou string que de ne a ordenação dos registros

integer

Número de recursões para tabelas relacionadas

$recursion

O método Model:: nd() funciona exatamente como Model:: ndAll() ,

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 $eld, string $value, mixed $conditions, mixed $order, string $limit, integer $recursion )

string $eld

Campo a ser utilizado como condicional

string $value

Valor usado como condição para o campo

mixed

Array ou string contendo condições adicionais para a busca

$conditions

mixed $order

Array ou string que de ne a ordenação dos registros

string $limit

Limite de registros a serem recuperados

integer

Número de recursões para tabelas relacionadas

$recursion

Model:: ndAllBy() busca todos os registros em que $ eld seja igual a

$value , usando $conditions como parâmetros adicionais. Seu retorno

é idêntico a Model:: ndAll() . Esse método é útil quando se quer usar

apenas um campo como condição para a busca:

$this->Users-> ndAllBy("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í ca:

$this->Users-> ndAllBy("level", "user", array("approved" => true));

Também é possível utilizar um atalho para essa função, Model:: ndAllBy< eld>() , onde $ eld é de nido no próprio nome da

função, e suprimido da lista de argumentos. Assim, $value se torna o

primeiro argumento.

$this->Users-> ndAllByLevel("user", array("approved" => true));

findBy( string $eld, string $value, mixed $conditions, mixed $order, integer $recursion )

string $eld

Campo a ser utilizado como condicional

string $value

Valor usado como condição para o campo

mixed

Array ou string contendo condições adicionais para a busca

$conditions

mixed $order

Array ou string que de ne a ordenação dos registros

integer

Número de recursões para tabelas relacionadas

$recursion

Model:: ndBy() funciona como Model:: ndAllBy() , exceto por

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

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

Model:: ndAllBy< eld>() :

$this->Users-> ndAllById(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 identi caçã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 modi cação de um registro. Para que você não precise explicitamente de nir valor para esses campos, o Spaghetti* faz isso para você.

Para que esse comportamento seja usado, é necessário ter os campos created ou modied de nidos como DATETIME em sua tabela. O campo created é de nido apenas uma vez, na criação do registro, e somente caso não tenha um valor já de nido em $data . Já o campo modi ed é rede nido a cada salvamento do registro, também somente caso não esteja de nido 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 veri caçã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
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 um registro seja apagado

$conditions

mixed $order

Array ou string que de ne a ordenação dos 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 su ciente 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 de nido em um lugar só!

class Posts extends AppModel { public function ndLastPosts() { return $this-> ndAll(array("created <" => "curda te()"), array("created" => "DESC"));

}

}

O método Posts:: ndLastPost() , depois de de nido, pode ser

utilizado normalmente dentro de um controller.

$this->Posts-> ndLastPosts();

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 é su cientemente óbvia, e naturalmente de nida. Por exemplo, uma postagem em um blog pertence a uma categoria, enquanto esse mesmo post possui vários comentários. Através dessa de niçã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

Relacionamento

Exemplos

hasOne

Um para um

Um usuário possui um per l

hasMany

Um para muitos

Um usuário possui vários posts

belongsTo

Muitos para um

Um usuário pertence a 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 per s.

Para de nir o relacionamento um para um em um modelo, é preciso de nir a variável hasOne , com um array contendo todos os outros modelos relacionados:

class Users extends AppModel { public $hasOne = array("Pro les");

}

Nota: Para relacionamentos hasOne , uma das tabelas deve ter a chave estrangeira correspondente. Em nosso caso, Pro les 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:: ndAll() , por exemplo.

$this->Users-> ndAll();

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

Array

(

[0] => Array

(

[id] => 1 [name] => admin, [password] => spaghettiphp [pro les] => Array

(

[id] => 1 [users_id] => 1

[realname] => Administrador do Site

)

)

[1] => Array

(

[id] => 2 [name] => root, [password] => root

[pro les] => Array

(

[id] => 2 [users_id] => 2 [realname] => Super Usuário

)

)

[2] => Array

(

[id] => 3 [name] => user

[password] => 123456 [pro les] => 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 de nir 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:: ndAll() . 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-> ndAll(array(), null, null, 1);

O

hasOne :

array retornado é apenas ligeiramente diferente do retornado por

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 de nir 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

Denindo Recursão

O Spaghetti* de ne 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 de nir uma recursão maior, ou mesmo menor. É possível modi car essa recursão padrão através da variável $recursion , de nida 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 de nir 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.

0

São retornados apenas os registros relacionados diretamente por hasOne e belongsTo

1

São retornados todos os registros relacionados diretamente pelo modelo, incluindo hasMany

n > 2

Além dos registros relacionados diretamente, retorna n níveis de recursão

Não é necessário de nir 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!

Denindo atributos para relacionamentos

O Spaghetti*, além de lhe prover várias convenções, também consegue

trabalhar muito bem sobre con guração. Você pode ter várias opções para de nir melhor seus relacionamentos.

Para de nir as opções de relacionamentos, é necessário modi car um pouco como os relacionamentos são de nidos. 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 de fi nir qualquer determina o nome da classe do modelo relacionado. Assim, é possível de nir 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ê determina o nome da chave estrangeira. Como o Spaghetti* ainda não conta com singularização/pluralização, você pode de nir 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 é 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ê di cilmente se deparará com elas, a menos em casos bem especí cos. 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 de nindo 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 con e 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 con guração.

Criando Controllers

Para criarmos um controller, é preciso de nir 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-> ndAll());

}

}

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 identi cação de um registro, para que ele possa ser identi cado no banco de dados. Quando esse ID é passado como terceira parte da URL, ele já é identi cado e enviado para o controller.

Para que uma action possa receber parâmetros, é necessário de ní-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-> ndById($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-> nd(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 de nir 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 cam 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 de nido um campo de nome id , o ID passado como parâmetro na URL não é passado para Controller::data , sendo necessário de ní-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", "Pro les");

}

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 de nir 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 de nição de modelos.

class UsersController extends AppController { public $uses = array("Users", "Pro les"); public $components = array("Auth"); public $helpers = array("Html", "Form", "Date");

}

A menos que você deseje incluir outros helpers, não é necessário de nir

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 de nir 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 de nido pelo controller. Para tal, de ne-se a variável pageTitle , com um texto qualquer que você queira ver no título.

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 zer 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 de nir 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 de nir 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 de nida.

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

beforeRender

Depois da execução da action, mas antes da 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 de ní-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 signi ca que todo e qualquer método ou atributo que for

de nido 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ê de nir 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 de nir um

layout especí co 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 pre ra utilizar outro arquivo,

pode alterar o layout padrão de nindo-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 de nidos 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.

Denindo um título para a página

Há uma maneira de de nir 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 ,

de nida dentro de um controller ou action (à sua escolha), onde você pode especi car 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 de nir 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í cas 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í cos 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, de nindo 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 de nir 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 m, caso precise gerar URL’s completas em seus links, de na 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

string $url

String contendo a URL da imagem

string $alt

String contendo o texto do atributo alt (conteúdo 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 )

mixed $url

String contendo a URL do arquivo CSS ou Array, 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:

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 m, caso precise gerar URL’s completas em suas tags style , de na 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 )

mixed $url

String contendo a URL do arquivo Javascript ou 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 m, caso precise gerar URL’s completas em suas tags script , de na

o terceiro parâmetro do método $html->script() como tru

<?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 $action

String opcional indicando a URL de ação do 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">

Especi cando uma URL de ação para o formulário

Para especi car 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 )

string $name

Nome do campo de formulário que você deseja 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("biogra a", "Nasci em São Paulo." , array("type"=>"textarea", "id"=>"suaBiogra a")); ?>

// Gerará o seguinte:

// <textarea name="nome" id="suaBiogra a">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"=>" le") ); ?>

// Gerará o seguinte:

// <input type=" le" 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 utilizá-lo

$buttonValue

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-sucientes, 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 ca 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 signi ca 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 con guraçã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 de ní-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 de nir isso dentro do controller, no callback beforeFilter() .

class AppController extends Controller { public $components = array("Auth"); public function beforeFilter() {

// de nindo o modelo de usuários $this->AuthComponent->userModel = "AppUsers"; // de nindo os campos de nome de usuário e senha $this->AuthComponent-> elds = 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 veri caçã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 de nido em // AuthComponent:: elds["username"] ?> <?php echo $form->input("password"); // deve ser o mesmo nome de nido em // AuthComponent:: elds["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 de nidas aos níveis de pre xo, controller e action, e são de nidas 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 pre xo $this->AuthComponent->allow(array("controller" => "users", "action" => "register")); $this->AuthComponent->allow(array("pre x" => "public"));

}

Às vezes, também é preciso veri car 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 veri caçã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 identi caçã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.

, passando como parâmetro o campo que se deseja retornar. $this->AuthComponent->user("id"); //

$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 criptogra a. O AuthComponent usa

hashes MD5, que são um tipo de criptogra a de apenas uma via, para armazenar senhas. Isso signi ca 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

de nido como campo de senha por AuthComponent-> elds["password"] .

Variáveis para personalização

Caso alguma das con gurações padrão do AuthComponent seja

diferente das suas necessidades, é possível personalizá-lo de forma que lhe atenda melhor. As variáveis con guráveis são:

Variável

Função

loginAction

URL para a qual o usuário será redirecionado quando não estiver autenticado

loginRedirect

URL para qual o usuário será redirecionado quando efetuar login

logoutRedirect

URL para a qual o usuário será redirecionado quando efetuar logout

Próximas etapas

Pois é, acredite se quiser: você chegou ao m do livro. Estamos felizes pelo seu interesse em 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 caremos 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
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.