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
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!
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.
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.
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.
$database = array(
"development" => array(
"host" => "localhost",
"user" => "username",
"password" => "password",
"database" => "spaghetti",
"prefix" => ""
)
);
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!
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");
Mapper::connect("/posts/:any", "/posts/view/$1");
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.
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");
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:
Buscando Registros
findAll( mixed $conditions, mixed $order, string $limit,
integer $recursion )
$conditions = array(
"username" => "admin",
"text LIKE" => "%spaghetti%"
);
// equivalente a
// username = "admin" AND text LIKE "%spaghetti%"
$this->Users->findAll($conditions);
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
)
)
Array
(
[id] => 1,
[username] => admin
[password] => spaghettiphp
)
$this->Users->findAllBy("level", "admin");
$this->Users->findAllById(1);
Salvando Registros
save( array $data )
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.
created e modified
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 )
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.
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.
$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.
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
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.
Nota: Para relacionamentos hasOne, uma das tabelas deve ter a chave
estrangeira correspondente. Em nosso caso, Profiles deveria possuir
o campo users_id.
$this->Users->findAll();
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
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
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.
É 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.
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.
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:
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:
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;
}
Caso você não deseje utilizar modelo algum em seu controller, basta
definir essa variável como um array vazio:
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.
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");
$this->redirect("/home", 404);
// gerando um erro 404 – página não encontrada
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.
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.
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.
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.
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.
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.
$this->set("fruits", array("lemon","orange","apple","grape"));
<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.
<html>
<head>
<title>My Page</title>
</head>
<body>
<h1>Welcome to My Page</h1>
</body>
</html>
$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
<?php
class AppController extends Controller {
public $layout = "login";
}
?>
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
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.
$options = array(
"selectedState" => "SP"
);
echo $this->element("formulario_dos_estados", $options);
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.
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:
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).
<h1>My Blog</h1>
<?php echo $number->ceil(2.0324); ?>
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ê.
// Gerará o seguinte:
// <a href="/recados/adicionar">Recados</a>
// Gerará o seguinte:
// <a href="http://www.google.com.br">Google</a>
// Gerará o seguinte:
// <a href="http://www.google.com.br" class="google-link"
>Google</a>
// Gerará o seguinte:
// <a href="/recados/adicionar"><img src=/images/botao_
adicionar.gif" alt="Adicionar Recado" /></a>
Por fim, caso precise gerar URL’s completas em seus links, defina o
quarto parâmetro do método $html->link() como true.
// Gerará o seguinte:
// <a href="http://suaapp.com/pagina/apagar">Apagar</a>
// Gerará o seguinte:
// <img src="http://www.suaaplicacao.com/images/natal/
foto01.jpg" alt="Foto de Natal" />
// Gerará o seguinte:
// <img src="http://google.com/coruja.gif" alt="Coruja" />
// Gerará o seguinte:
// <img src="/images/papagaio.gif" alt="Papagaio" class=
"foto" />
// Gerará o seguinte:
// <link href="/styles/default.css" rel="stylesheet"
type="text/css" />
// Gerará o seguinte:
// <link href="http://www.google.com/default.css" rel=
"stylesheet" type="text/css" />
// Gerará o seguinte:
// <link href="/styles/default.css" rel="stylesheet"
type="text/css" />
// Gerará o seguinte:
// <link href="/styles/default.css" rel="stylesheet"
type="text/css" media="handheld" />
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" />
// Gerará o seguinte:
// <script src="/scripts/default.js"
type="text/javascript"></script>
// Gerará o seguinte:
// <script src="http://www.google.com/default.js"
type="text/javascript"></script>
// Gerará o seguinte:
// <script src="/scripts/default.js"
type="text/javascript"> </script>
// <script src="/scripts/jquery.js"
type="text/javascript"> </script>
// Gerará o seguinte:
// <script src="/scripts/default.js"
type="text/javascript" defer="defer"></script>
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.
// Gerará o seguinte:
// <form action="http://suaapp.com/url_atual_da_pagina"
method="post">
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().
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().
// Gerará o seguinte:
// <form action="http://suaapp.com/url_atual_da_pagina"
method="get">
// Gerará o seguinte:
// <input type="text" name="nome" value="João da Silva"
id="seuNome" />
// Gerará o seguinte:
// <textarea name="nome" id="suaBiografia">Nasci em
São Paulo.</ textarea>
// Gerará o seguinte:
// <input type="password" name="senha" id="suaSenha" />
// Gerará o seguinte:
// <select name="estado">
// <option name="rj" selected="selected">Rio</option>
// <option name="sp">São Paulo</option>
// </select>
// 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.
// Gerará o seguinte:
// </form>
// Gerará o seguinte:
// <input type="submit" name="Enviar" />
// </form>
// Gerará o seguinte:
// <input type="submit" name="Enviar" id="submitButton" />
// </form>
// 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.
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.
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.
$this->UploadComponent->upload()
$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!
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.
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
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.