Spaghetti Php

March 20, 2018 | Author: Evandro Guimarães Demuth | Category: Php, Regular Expression, Sql, Html, Class (Computer Programming)


Comments



Description

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 filosofia. Uma filosofia de desenvolvimento produtivo e divertido, com qualidade de código. O Spaghetti* tem feito nosso dia melhor, e acreditamos que ele também pode fazer o seu e de sua equipe. Um forte abraço da equipe do Spaghetti* Seja bem vindo! Seja bem vindo ao primeiro livro do Spaghetti*! Aqui você pode descobrir um pouco mais sobre nosso framework, suas características e funcionalidades. Seja uma pequena dúvida ou uma grande curiosade, você encontrará aqui! Além de entregar um framework de qualidade, também nos preocupamos em mantê-lo bem documentado, para que qualquer um possa aprender a usá-lo, e tornar seu trabalho cada vez melhor. O resultado é essa documentação em formato de livro que, apesar de se manter simples, é compreensiva o bastante para cobrir todos os aspectos pertinentes do Spaghetti*. Começando Se você é novo no mundo do Spaghetti*, pode começar descobrindo um pouco mais sobre este framework, o que ele faz e por que você pode usá-lo. Mas se você já é mais experiente e sabe o que procurar, pode se guiar pela documentação on-line, ou ainda conhecer o código-fonte do Spaghetti* de perto. Como obter ajuda Caso este libro não seja suficiente, você encontra em nosso site tutoriais e screencasts, além da documentação mais atualizada. Introdução sobre MVC O Spaghetti* foi construído baseando-se no design pattern MVC, separando as camadas da sua aplicação, tornando o desenvolvimento e manutenção muito mais fáceis e rápidos. Na prática, toda a camada de lógica e dados fica separada da camada de apresentação de sua aplicação, mantendo seu código PHP longe do código HTML, fazendo com que designers e programadores possam trabalhar simultaneamente de maneira harmoniosa e eficiente. Modelos de Dados Os modelos de dados, ou Models, representam os dados de sua aplicação. Embora os dados geralmente venham de bancos de dados como MySQL, SQL Server e similares, eles podem ser basicamente qualquer coisa, desde arquivos de texto até documentos em XML. O limite é a sua criatividade. As classes do Spaghetti* irão auxiliá-lo na manipulação de seus dados, sem que você precise escrever uma única linha de SQL. O Spaghetti* faz o trabalho sujo, enquanto você se preocupa com o que realmente interessa. No momento, os modelos de dados do Spaghetti* funcionam apenas com MySQL, embora o suporte a outros bancos de dados já esteja previsto para a próxima versão. Isso também significa que, se não existir um driver para o banco de dados que você usa, você mesmo poderá criá-lo e compartilhar com a comunidade do Spaghetti*. Controladores É nos Controllers que a mágica realmente acontece. É aqui onde você irá tratar as respostas do usuário, buscar e processar dados e retorná-los para as Views. Nada de código HTML, nada de CSS, nada de JavaScript. Única e puramente código PHP. Mesmo você estando no comando, o Spaghetti* irá lhe auxiliar dando acesso aos seus Models e facilitando o envio de dados para as Views. Você se diverte programando, e o Spaghetti* o ajuda com o resto. Visualizações As Views fazem parte da camada de apresentação de sua aplicação. Nessa camada você se preocupa unicamente em mostrar os dados ao usuário, usando apenas algumas estruturas básicas em PHP, evitando aquela típica mistura de lógica e apresentação em um mesmo arquivo. Além disso, também é possível usar comandos para a criação fácil de links, imagens e formulários, sem que você precise se preocupar com detalhes chatos de implementação. Escolhemos o MVC por ser um pattern que faz bastante sentido no desenvolvimento Web, além de aumentar a produtividade, diminuir a repetição de código, facilitar a correção de bugs e tornar a vida dos desenvolvedores um pouco mais divertida. E você, está pronto para entrar brincadeira, e se unir a nós por um desenvolvimento melhor? Configurando sua aplicação Gigantescos arquivos de configuração? Não nesse framework. Qualquer aplicação do Spaghetti* já está pronta para ser desenvolvida em questão de segundos! Configurar o Spaghetti* é realmente muito fácil. Embora algumas outras configurações sejam possíveis, a única coisa que você necessita para ter uma aplicação rodando é definir as configurações de seu banco de dados. Configurando o banco de dados Para configurar seu banco de dados, você precisa editar o arquivo app/config/database.php. O Spaghetti* já vem com uma configuração de exemplo, você só precisa alterar os campos necessários, e sua configuração ficará assim: $database = array( "development" => array( "host" => "localhost", "user" => "username", "password" => "password", "database" => "spaghetti", "prefix" => "" ) ); O Spaghetti* suporta configurações diferentes para cada ambiente de desenvolvimento. No exemplo acima, definimos o ambiente development, mas também podemos definir quantos mais forem necessários. Isso evita que você sobrescreva configurações, facilitando o deploy da aplicação. Escolhendo o Ambiente Para escolher o ambiente que você deseja usar, basta alterar a configuração environment no arquivo app/config/settings.php: Config::write("environment", "development"); E o que mais? Apesar de você poder customizar um pouco mais sua aplicação, você não precisa mais nada para começar sua aplicação. O Spaghetti* prefere convenção em vez de configuração, e todo o resto é deduzido através da estrutura do framework. Agora você está pronto pra começar a trabalhar! Rotas URLs complicadas, sem sentido ou apenas longas demais são um problema comum. Entretanto, com as rotas do Spaghetti* a solução é simples e rápida, e você nem mesmo precisará escrever mais do que algumas linhas! Nem sempre a estrutura padrão controller/action/id é a melhor ou mais indicada para sua aplicação. Embora faça sentido, você pode precisar fazer suas próprias modificações nessa estrutura. Esse é o propósito do arquivo app/config/routes.php. Rotas Padrão Quando você abrir o arquivo de configuração de rotas, você já encontrará uma chamada ao método Mapper::connect(), definindo a rota padrão de sua aplicação. Mapper::connect("/", "/home"); A rota acima vinculará a raiz de sua aplicação com o HomeController. Essa rota pode apontar para qualquer outro controller de sua aplicação, mas ela é necessária pois o Spaghetti* precisa saber como proceder quando nenhum controller é especificado na URL. Caso contrário, será chamada a classe Controller, que é apenas uma classe base, e não um controller propriamente dito. Definindo novas rotas A definição de novas rotas modificará a resposta de sua aplicação de acordo com a URL acessada. As rotas devem ser definidas no mesmo arquivo app/config/routes.php, pois ele é chamado antes de qualquer processamento do Spaghetti*. Para conectar novas rotas a determinadas URLs, utilizamos o método Mapper::connect(), que deve receber dois parâmetros: o padrão a ser comparado e a rota que esse padrão deve seguir. Ou seja, o padrão será a URL acessada, e a rota será o caminho que essa URL terá. Com a rota abaixo, por exemplo, a URL /posts/definindo-novas-rotas aponta para /posts/view/definindo-novas-rotas: Mapper::connect("/posts/:any", "/posts/view/$1"); O Mapper::connect() tem suporte a expressões regulares, tornando a comparação ainda mais poderosa. Entretanto, para evitar que você tenha que escrever expressões, o Spaghetti* já possui algumas strings “mágicas” para os casos mais comuns: :any corresponde a qualquer caracter, incluindo barras :num corresponde a qualquer número, mas não inclui barras :part corresponde a qualquer caracter, seja ele dígito ou número, mas não considera barras Para recuperar essas ocorrências depois, usamos a mesma sintaxe usada em expressões regulares: $1 retorna a primeira ocorrência, $2 retorna a segunda ocorrência, e assim sucessivamente. Nota: Para que expressões regulares sejam retornadas depois, é necessário que estejam entre parênteses. Definindo prefixos Várias aplicações necessitam de áreas distintas dentro de sua estrutura. Mais do que apenas controllers diferentes, às vezes se torna necessário realizar as mesmas ações, mas por usuários com permissões diferentes. Isso acontece quando é necessária uma seção para administração, por exemplo. Para esse tipo de necessidade, o Spaghetti* conta com prefixos, através do método Mapper::prefix(): Mapper::prefix("admin"); Quando um prefixo é definido, o Spaghetti* passa a chamar actions diferentes. Quando a URL /admin/users for chamada, será chamada a action admin_index de UsersController, em vez de apenas index. Com essas ações distintas, é possível manter níveis de permissão, além da possibilidade de alterar o comportamento de cada ação. Nota: Prefixos também estão sujeitos a ação de rotas, ou seja, uma rota pode redirecionar um prefixo e causar problemas em sua aplicação. Caso você queira definir vários prefixos, também é possível fazê-lo com apenas uma chamada ao método, passando vários argumentos: Mapper::prefix("admin", "user"); Através da criação de múltiplos prefixos você pode segmentar sua aplicação, criando várias áreas distintas, com uma estrutura flexível e bem definida. Models Você não precisa escrever tanto SQL. Os modelos de dados do Spaghetti*, além de facilitarem a iteração entre registros, também geram todo o SQL necessário para as suas consultas, através de arrays simples, apenas com código PHP. Os models do Spaghetti são os responsáveis por todas as tarefas de banco de dados. Desde criar e alterar registros até buscas complexas e relacionamentos entre tabelas, sem escrever uma única linha de SQL. Mas não se preocupe: caso você precise ser ainda mais específico, você também pode digitar diretamente suas consultas. Criando Modelos Dentro da estrutura de arquivos do Spaghetti*, os modelos se encontram em app/models, e seguem a convenção nome_do_modelo.php. Basicamente, um modelo é apenas uma definição de classe vazia: class Users extends AppModel { } Através da extensão da classe AppModel, Users herda todos os métodos necessários para qualquer operação de banco de dados. Além disso, o Spaghetti* já assume que o nome da tabela do banco de dados associada a esse modelo chama-se users. Entretanto, caso você use nomes de tabelas diferentes dos nomes dos modelos, é possível definir o nome manualmente através da variável table. class Users extends AppModel { public $table = "users_table"; } Buscando Registros findAll( mixed $conditions, mixed $order, string $limit, integer $recursion ) mixed $conditions mixed $order string $limit integer $recursion Array ou string contendo as condições para a busca Array ou string que define a ordenação dos registros Limite de registros a serem recuperados Número de recursões para tabelas relacionadas O método Model::findAll() retorna todos os registros que obedeçam à condição $conditions especificada, ordenados por $order, limitando a $limit registros. O parâmetro $conditions pode ser uma string SQL qualquer, como username = "admin" ou text LIKE "%spaghetti%". Entretanto, você não estaria usando de todo o potencial do Spaghetti*. Através de arrays, é possível criar uma gama enorme de condições diferentes. $conditions = array( "username" => "admin", "text LIKE" => "%spaghetti%" ); // equivalente a // username = "admin" AND text LIKE "%spaghetti%" $this->Users->findAll($conditions); Além de consultas simples como as usadas acima, o Spaghetti* também permite condições mais complexas, como você pode descobrir em Condições Complexas. A ordenação de registros funciona de maneira semelhante, utilizando strings ou arrays. Arrays seguem a seguinte estrutura: $order = array("id" => "ASC", "date" => "DESC"); O retorno do método é um array contendo vários outros arrays, tendo como chaves os nomes dos campos, pronto para uso em blocos for e foreach, como qualquer outro array. Array ( [0] => Array ( [id] => 1 [name] => admin, [password] => spaghettiphp ) [1] => Array ( [id] => 2 [name] => root, [password] => root ) [2] => Array ( [id] => 3 [name] => user [password] => 123456 ) ) find( mixed $conditions, mixed $order, integer $recursion ) mixed $conditions mixed $order integer $recursion Array ou string contendo as condições para a busca Array ou string que define a ordenação dos registros Número de recursões para tabelas relacionadas O método Model::find() funciona exatamente como Model::findAll(), exceto por retornar apenas o primeiro registro que obedeça às condições passadas. A estrutura do array também é ligeiramente diferente, sendo unidimensional: Array ( [id] => 1, [username] => admin [password] => spaghettiphp ) findAllBy( string $field, string $value, mixed $conditions, mixed $order, string $limit, integer $recursion ) string $field string $value mixed $conditions mixed $order string $limit integer $recursion Campo a ser utilizado como condicional Valor usado como condição para o campo Array ou string contendo condições adicionais para a busca Array ou string que define a ordenação dos registros Limite de registros a serem recuperados Número de recursões para tabelas relacionadas Model::findAllBy() busca todos os registros em que $field seja igual a $value, usando $conditions como parâmetros adicionais. Seu retorno é idêntico a Model::findAll(). Esse método é útil quando se quer usar apenas um campo como condição para a busca: $this->Users->findAllBy("level", "admin"); Apesar do propósito da função ser a busca por apenas um campo, é possível adicionar outros campos como condições adicionais, tornando a busca um pouco mais específica: $this->Users->findAllBy("level", "user", array("approved" => true)); Também é possível utilizar um atalho para essa função, Model::findAllBy<field>(), onde $field é definido no próprio nome da função, e suprimido da lista de argumentos. Assim, $value se torna o primeiro argumento. $this->Users->findAllByLevel("user", array("approved" => true)); findBy( string $field, string $value, mixed $conditions, mixed $order, integer $recursion ) string $field string $value mixed $conditions mixed $order integer $recursion Campo a ser utilizado como condicional Valor usado como condição para o campo Array ou string contendo condições adicionais para a busca Array ou string que define a ordenação dos registros Número de recursões para tabelas relacionadas Model::findBy() funciona como Model::findAllBy(), exceto por retornar apenas o primeiro item encontrado, em um array unidimensional. Assim como Model::findAllBy(), também aceita o atalho Model::findAllBy<field>(): $this->Users->findAllById(1); Salvando Registros save( array $data ) array $data Dados a serem salvos O salvamento de registros é sempre algo complicado. Primeiro é necessário saber se um registro existe, para depois podermos decidir se ele deve ser inserido ou se deve ser apenas atualizado. Com o Spaghetti*, você se preocupa apenas em enviar os dados, e o resto é trabalho do framework. Para que o Spaghetti* possa salvar corretamente os dados, o array $data deve ser construído assim: Array ( [id] => 1, [username] => admin [password] => spaghettiphp ) Caso algum campo não seja passado, ele não será considerado na consulta SQL, ou seja, ele permanecerá intacto na tabela, caso exista. Se você passar algum campo inexistente, ele será completamente desconsiderado, então não é necessário se preocupar em limpar arrays vindos de formulários. Para que o modelo possa descobrir se o registro já existe na tabela, é necessário que seja passado o campo id. É realizada uma busca na tabela, e caso outro registro com mesma identificação já exista, ele é atualizado. Caso contrário, ele é criado. Tudo isso na mesma função, sem você precisar se preocupar. Quando estiver usando Model::save() dentro de loops, não esqueça de usar Model->create() para evitar que os dados sejam sobrescritos. created e modified Muitas vezes é necessário manter registro das datas de criação e modificação de um registro. Para que você não precise explicitamente definir valor para esses campos, o Spaghetti* faz isso para você. Para que esse comportamento seja usado, é necessário ter os campos created ou modied definidos como DATETIME em sua tabela. O campo created é definido apenas uma vez, na criação do registro, e somente caso não tenha um valor já definido em $data. Já o campo modified é redefinido a cada salvamento do registro, também somente caso não esteja definido em $data. Prevenção contra SQL Injection Também somos preocupados com segurança. Por isso, toda e qualquer string usada como valor é passada pelo método Model::escape(), escapando qualquer caracter que possa ser perigoso caso esteja em uma consulta SQL. E não se preocupe com magic_quotes, o modelo já faz a verificação e elimina barras quando necessário. Caso você precise fazer consultas de maneira manual, ou precise escapar qualquer string dentro da aplicação, basta usar essa mesma função. $this->Users->escape("String 'potencialmente' perigosa"); // Retorna "String \'potencialmente\' perigosa" saveAll( array $data ) array $data Dados a serem salvos Caso você precise salvar vários registros de uma só vez, o Spaghetti* lhe dá a opção do método Model::saveAll(). Ele dispõe de todas as funcionalidades de Model::save(), com exceção do parâmetro recebido. Esse parâmetro deve ser um array com a seguinte estrutura: Array ( [0] => Array ( [id] => 1 [name] => admin, [password] => spaghettiphp ) [1] => Array ( [id] => 2 [name] => root, [password] => root ) [2] => Array ( [id] => 3 [name] => user [password] => 123456 ) ) Apagando Registros delete( integer $id ) integer $id ID do registro a ser apagado Model::delete() apaga apenas um registro com ID $id da tabela. Como ele é limitado a apenas um registro, mesmo que existam vários IDs iguais, apenas o primeiro será apagado. deleteAll( mixed $conditions, mixed $order, integer $limit ) mixed $conditions mixed $order integer $limit Array ou string contendo as condições para que um registro seja apagado Array ou string que define a ordenação dos registros a serem apagados Limite de registros apagados Model::deleteAll() faz a remoção de vários registros de uma única vez, apagando registros que obedeçam às condições $conditions, ordenados por $order e limitados por $limit. Esse método é útil quando é necessário apagar vários registros, que não obedeçam apenas a IDs, como usuários não aprovados ou mensagens de spam. $this->Users->deleteAll(array("approved" => false)); Métodos Personalizados Os modelos de dados do Spaghetti* são poderosos o suficiente para prover todas as funcionalidades básicas que você precisa para desenvolver sua aplicação sem se preocupar com detalhes como escrever SQL. Entretanto, você pode precisar de um pouco mais. Não esqueça que as classes de modelo podem ser estendidas: basta você adicionar métodos e propriedades! Qualquer função repetitiva relacionada a banco de dados deve ser escrita aqui. Depois, você poderá usá-la em qualquer controller que use esse modelo. DRY, tudo definido em um lugar só! class Posts extends AppModel { public function findLastPosts() { return $this->findAll(array("created <" => "curda te()"), array("created" => "DESC")); } } O método Posts::findLastPost(), depois de definido, pode ser utilizado normalmente dentro de um controller. $this->Posts->findLastPosts(); Relacionamentos entre Models Os relacionamentos entre modelos são uma das características mais poderosas do Spaghetti*. Através deles, é possível mapear as associações entre tabelas, tornando mais fácil o trabalho com dados relacionados. A necessidade de relacionamentos é suficientemente óbvia, e naturalmente definida. Por exemplo, uma postagem em um blog pertence a uma categoria, enquanto esse mesmo post possui vários comentários. Através dessa definição, é possível acessar registros relacionados entre si, retornando-os em apenas uma consulta. Tipos de Relacionamentos Até a versão atual, o Spaghetti* trabalha com 3 tipos diferentes de associações: um para um, um para muitos e muitos para um. Tipo de Relacionamento hasOne hasMany belongsTo Relacionamento Um para um Um para muitos Muitos para um Exemplos Um usuário possui um perfil Um usuário possui vários posts 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 perfis. Para definir o relacionamento um para um em um modelo, é preciso definir a variável hasOne, com um array contendo todos os outros modelos relacionados: class Users extends AppModel { public $hasOne = array("Profiles"); } Nota: Para relacionamentos hasOne, uma das tabelas deve ter a chave estrangeira correspondente. Em nosso caso, Profiles deveria possuir o campo users_id. Através desse relacionamento, é possível retornar todas as informações de um usuário, com apenas uma chamada ao método Users::findAll(), por exemplo. $this->Users->findAll(); Através da consulta acima, é retornado um array com a seguinte estrutura: Array ( [0] => Array ( [id] => 1 [name] => admin, [password] => spaghettiphp [profiles] => Array ( [id] => 1 [users_id] => 1 [realname] => Administrador do Site ) ) [1] => Array ( [id] => 2 [name] => root, [password] => root [profiles] => Array ( [id] => 2 [users_id] => [realname] => ) ) [2] => Array ( [id] => 3 [name] => user [password] => 123456 [profiles] => Array ( [id] => 3 [users_id] => [realname] => ) ) ) 2 Super Usuário 3 Usuário Comum hasMany Um relacionamento um para muitos, assim como seu inverso, é um dos mais comuns. Ele acontece quando um registro em determinada tabela possui mais de um registro correspondente em outra tabela. Por exemplo, um usuário pode ter vários posts, ou um post pode ter vários comentários. Para definir um relacionamento um para muitos, é preciso declarar a variável hasMany no modelo de dados. class Users extends AppModel { public $hasMany = array("Posts"); } Assim como em hasOne, também é possível acessar os registros correspondentes através de métodos como Model::findAll(). Entretanto, por padrão o Spaghetti* retorna apenas os dados de relacionamentos belongsTo e hasOne, para evitar a sobrecarga de seu banco de dados. Para retornar registros de hasMany, é necessário passar o parâmetro $recursion: $this->Users->findAll(array(), null, null, 1); O array retornado é apenas ligeiramente diferente do retornado por hasOne: Array ( [0] => Array ( [id] => 1 [name] => admin, [password] => spaghettiphp [posts] => Array ( [0] => Array ( [id] => 1 [users_id] [title] => ) ) ) [1] => Array ( [id] => 2 [name] => root, [password] => root [posts] => Array ( [0] => Array ( [id] => 2 [users_id] [title] => ) [1] => Array ( [id] => 3 [users_id] [title] => ) ) ) ) => 1 Meu Primeiro Post => 2 Esse é outro. => 2 Mais um post meu =P Nota: nesse caso, a chave estrangeira deve estar presente apenas no modelo relacionado, e não naquele em que se descreve o relacionamento. belongsTo Relacionamentos muitos para um são exatamento o inverso de relacionamentos um para muitos. Embora não seja necessário, acontece em qualquer lado oposto de um relacionamento hasMany. Acontece quando um post pertence a um usuário, ou quando um post pertence a uma categoria. Para descrever um relacionamento muitos para um, é necessário definir a variável belongsTo no modelo desejado: class Comments extends AppModel { public $belongsTo = array("Posts"); } Nota: em relacionamentos belongsTo, a chave estrangeira deve estar presente apenas na tabela em que se descreve o relacionamento, e não no modelo relacionado, justamente o contrário de relacionamentos hasMany Definindo Recursão O Spaghetti* define uma recursão padrão para seus modelos, para que você não precise se preocupar com sobrecarga em seu servidor de banco de dados. Entretanto, muitas vezes é necessário definir uma recursão maior, ou mesmo menor. É possível modificar essa recursão padrão através da variável $recursion, definida na classe dos modelos de dados. class Users extends AppModel { public $recursion = 1; } Caso esse número de recursões seja compartilhado entre todos os modelos de sua aplicação, você pode criar o modelo AppModel em app/models/app.php, e definir a mesma variável. class AppModel extends Model { // aqui estendemos Model em vez de AppModel! public $recursion = 1; } O valor da recursão pode variar dependendo de sua necessidade. Os valores possíves variam desde -1 até qualquer número positivo. Recursão -1 0 1 n>2 Dados retornados Nenhum registro relacionado é retornado. São retornados apenas os registros relacionados diretamente por hasOne e belongsTo São retornados todos os registros relacionados diretamente pelo modelo, incluindo hasMany Além dos registros relacionados diretamente, retorna n níveis de recursão Não é necessário definir níveis de recursão maiores do que o necessário. Isso pode diminuir a velocidade de sua aplicação, assim como causar sobrecarga em seu servidor. Use com responsabilidade! Definindo atributos para relacionamentos O Spaghetti*, além de lhe prover várias convenções, também consegue trabalhar muito bem sobre configuração. Você pode ter várias opções para definir melhor seus relacionamentos. Para definir as opções de relacionamentos, é necessário modificar um pouco como os relacionamentos são definidos. Em vez de apenas um array numerado, é necessário nomeá-lo, da seguinte maneira: public $hasMany = array("assocName" => array("option" => "value")); className determina o nome da classe do modelo relacionado. Assim, é possível definir qualquer nome para a associação, sem que a associação pare de funcionar. foreignKey determina o nome da chave estrangeira. Como o Spaghetti* ainda não conta com singularização/pluralização, você pode definir manualmente um nome no singular, ou mesmo qualquer outro nome, para a chave. conditions é um array ou string de condições. Somente os registros que obedeçam a essa condição serão adicionados à associação. Condições Complexas Arrays simples não dão conta de suas necessidades de SQL? Tudo bem, o Spaghetti* ainda lhe dá mais poder na hora de gerenciar suas consultas. Com o Spaghetti*, a escrita de consultas SQL é tão rara que você dificilmente se deparará com elas, a menos em casos bem específicos. Com o uso de arrays, é possível criar condições facilmente, de leitura e manutenção extremamente simples. Basicamente, um array de condições contém pares de chaves e valores definindo cada declaração. A condição abaixo, por exemplo, encontrará registros em que title é igual a Hello World. $conditions = array("title" => "Hello World"); É tão simples que você esquecerá que um dia precisou escrever SQL. Mas isso não é tudo, é possível mais! Para adicionar outras declarações à condição, basta adicionar outro item ao array. $conditions = array("id" => "3", "title" => "Hello World"); Agora vamos a outros tipos de comparações. E se você estiver procurando um registro no qual o título NÃO seja Hello World? $conditions = array("title <>" => "Hello World"); Usando o operador SQL <>, o Spaghetti* encontrará registros em que o título seja diferente de Hello World. Além desse operador, você pode usar qualquer outro operador SQL válido, como >, < e LIKE, e o Spaghetti* o reconhecerá e montará a consulta. Para que o operador SQL seja reconhecido como tal, é necessário que ele esteja separado do nome do campo por um espaço. Além de comparações com um valor, também é possível usar comparações com um conjunto de valores, como em uma consulta IN: $conditions = array("title" => array("Primeiro Post", "Segundo Post", "Terceiro Post")); Esse mesmo princípio funciona com diferentes campos em uma mesma condição OR: $conditions = array(array("id" => 3, "title" => "Hello World")); Consultas BETWEEN também são criadas facilmente, basta adicionar o operador BETWEEN juntamente com o nome do campo. $conditions = array("id BETWEEN" => array(1, 15)); Embora o Spaghetti* cuide do trabalho sujo para você, algumas vezes é necessário sujar as mãos e escrever SQL diretamente. Para isso, você só precisa passar uma string como parâmetro. $conditions = "id = 1 AND title = 'Hello World'"; Nota: em consultas manuais, os valores não são escapados pelo Spaghetti*. Nunca confie em dados vindos do usuário, e sempre use Model::escape() para fazer o escape de valores. Controllers É nos controllers onde tudo acontece. Aqui você começa a programar de verdade, e a usar de todo o poder do Spaghetti*. Os controllers trabalham com toda a lógica da aplicação. Tarefas como o processamento de dados vindos do usuário, a busca de registros no banco de dados através dos models e a passagem dos dados para as views. Geralmente, controllers são associados a um único modelo. Para facilitar seu trabalho, o Spaghetti* já associa por padrão seu controller com um model de mesmo nome, sem necessitar de nenhuma configuração. Criando Controllers Para criarmos um controller, é preciso definir a classe <nome>Controller, e salvá-la em app/controllers /<nome>_controller.php. Também é necessário estender a classe AppController, para que todos os métodos necessários sejam herdados, e sua aplicação funcione corretamente. class PostsController extends AppController { } A partir de agora, a URL /posts já está disponível, embora retorne um erro dizendo que a action ainda não existe. Precisamos resolver isso! Criando Actions Actions nada mais são do que métodos dentro de uma classe de controller. Cada action corresponde a uma ação diferente de sua aplicação. Ações podem ser o envio de um e-mail, o cadastro de um usuário, a postagem de um artigo, entre qualquer outra coisa. Para que sua aplicação funcione, é necessária a criação de actions e suas respectivas views. Vamos criar uma action simples, para gerar uma lista de posts: class PostsController extends AppController { public function index() { $this->set("posts", $this->Posts->findAll()); } } A primeira coisa que devemos saber para podermos interagir entre controllers e views é como se faz a passagem de variáveis. Para isso, usa-se o método Controller::set, passando como parâmetros o nome da variável e seu respectivo valor. Dentro da view, essa variável estará disponível como uma variável local comum, acessível por $posts, no nosso caso. Você também pode notar que o modelo de dados já está disponível em $this->Posts. Através desse objeto, é possível acessar todas as propriedades do model Posts (que já deve existir em app/models /posts.php). A partir de agora, se a view já tiver sido criada em app/views/posts /index.phtm, você já poderá ver o resultado em /posts. Como nenhuma action é passada pela URL, o Spaghetti* supõe que esta seja index. Qualquer outra action pode ser acessada através da estrutura /controller/action. Recebendo parâmetros Diferente de páginas PHP comuns, os parâmetros no Spaghetti* não são passados através de query strings, como ?id=1&page=2. Eles são passados como parte da URL, com cada parâmetro gerando uma URL diferente. O parâmetro mais usado é um número de identificação de um registro, para que ele possa ser identificado no banco de dados. Quando esse ID é passado como terceira parte da URL, ele já é identificado e enviado para o controller. Para que uma action possa receber parâmetros, é necessário definí-los na função. Em uma ação de visualização de posts, pode-se fazer assim: public function view($id = null) { $this->set("post", $this->Posts->findById($id)); } É recomendável que todo parâmetro tenha um valor padrão. Caso contrário, se esse parâmetro não for passado, o PHP disparará um erro, quebrando sua aplicação. Além do ID, é possível passar qualquer outro parâmetro, bastando adicionar mais partes na URL. Esse parâmetros são passados sequencialmente para a action. Para receber os parâmetro passados pela URL /posts/view/1/hello-world, nossa action precisaria mudar para: public function view($id = null, $slug = "") { $this->set("post", $this->Posts->find(array("id" => $id, "slug" => $slug))); } Nota: mesmo quando não estiver presente na URL, o ID é passado como um valor nulo para a action. Caso você esteja usando parâmetros textuais, é necessário definir o primeiro parâmetro mesmo assim. Recebendo Dados do Usuário Além de receber parâmetros como ID, também é necessário receber os dados enviados pelo usuário através do método POST. Assim que o usuário envia uma requisição a partir de um formulário, todos os dados de $_POST ficam disponíveis através da variável Controller::data. Quando esses dados são recebidos, eles já estão prontos para serem usados em qualquer consulta Model::save(), bastando passá-los como parâmetro. public function add() { if(!empty($this->data)): $this->Posts->save($this->data); endif; } E lembre-se: a menos que seja definido um campo de nome id, o ID passado como parâmetro na URL não é passado para Controller::data, sendo necessário definí-lo manualmente. public funcion edit($id = null) { if(!empty($this->data)): $this->data["id"] = $id; $this->Posts->save($this->data); endif; } Modelos, Helpers e Componentes Por padrão, o Spaghetti* já vincula seu controller com um modelo de mesmo nome. Entretanto, você pode precisar usar um modelo diferente em determinados controllers, ou mesmo usar vários modelos dentro de um mesmo controller. Para isso, o Spaghetti* usa a variável uses. class UsersController extends AppController { public $uses = array("Users", "Profiles"); } Nota: Não é necessário incluir modelos relacionados caso eles não sejam usados diretamente, o Spaghetti* já se encarrega disso! Caso você não deseje utilizar modelo algum em seu controller, basta definir essa variável como um array vazio: class UsersController extends AppController { public $uses = array(); } Os componentes e helpers desejados também devem ser incluídos no controller, através de suas respectivas variáveis components e helpers, assim como na definição de modelos. class UsersController extends AppController { public $uses = array("Users", "Profiles"); public $components = array("Auth"); public $helpers = array("Html", "Form", "Date"); } A menos que você deseje incluir outros helpers, não é necessário definir Html e Form, já que eles são herdados de AppController. Usando Layouts Fazendo o uso de layouts, você economiza código HTML, gerando todo o esqueleto da página apenas uma vez. Por padrão, o Spaghetti* renderiza o layout default, que se encontra em app/layouts /default.phtm. Entretanto, é possível escolher qualquer outro layout disponível em sua aplicação através da variável layout. class HomeController extends AppController { public $layout = "home"; } Muitas vezes um layout não é necessário, e você deseja que o Spaghetti* não renderize nenhum. Nesse caso, é possível definir o valor da variável como false e pronto! Também usado geralmente nos layouts, o título da página também pode ser definido pelo controller. Para tal, define-se a variável pageTitle, com um texto qualquer que você queira ver no título. class HomeController extends AppController { public $pageTitle = "Minha Aplicação com Spaghetti*"; } Essa variável também é recebida como uma variável local, tanto em views quanto em layouts. Você pode imprimí-la onde desejar, seja na tag <title>, em tags <h1>, ou onde mais se fizer necessário. Redirecionamentos Após uma ação, geralmente após editar ou apagar algum registro, geralmente acontece um redirecionamento da aplicação. Os controllers do Spaghetti* já herdam o método Controller::redirect() para esse propósito. Basta definir a URL para a qual se deseja redirecionar. $this->redirect("/home"); Como o redirecionamento é feito através de um header HTTP, também é possível adicionar mais um header indicando o status da requisição. Basta passar como segundo parâmetro o número do status, e o Spaghetti* se encarrega de definir o header apropriado: $this->redirect("/home", 404); // gerando um erro 404 – página não encontrada Além de redirecionamentos HTTP, o Spaghetti* também suporta que você redirecione uma ação para outra do mesmo controller. Isso é feito através do método Controller::setAction(), passando o nome da ação como parâmetro. Qualquer outro parâmetro será passado diretamente para a action definida. Esse método é bastante útil para evitar a criação de várias views para ações semelhantes, como adicionar e editar registros, por exemplo. public function add() { $this->setAction("edit"); } public function edit($id = null) { if(!empty($this->data)): $this->data["id"] = $id; $this->Posts->save($this->data); endif; } Callbacks Os callbacks são funções executadas em determinados momentos da execução do Spaghetti*, como antes da execução de uma ação do controller ou antes da renderização de uma view. Callback beforeFilter beforeRender afterFilter Momento da execução Antes da execução da action Depois da execução da action, mas antes da renderização da view Após execução da action e renderização da view Esse callbacks podem ser usados para executar qualquer coisa que você precise para seus controllers. Para definí-los, basta criar sua função correspondente na classe de controller. class HomeController extends AppController { public function beforeFilter() { $this->AuthComponent->check(); } } AppController AppController é o controller base para todos os outros controllers na aplicação. Isso significa que todo e qualquer método ou atributo que for definido dentro dessa classe estará disponível para todos os outros controllers da aplicação. O uso dessa herança é muito útil no uso de callbacks, quando é necessário que eles sejam executados em todas as partes da aplicação. O componente AuthComponent, por exemplo requer que o método check seja executado em todas as partes da aplicação. Por padrão, o Spaghetti* usa o AppController da biblioteca padrão. Entretanto, você pode criar o arquivo app/controllers /app_controller.php, e então o Spaghetti* passará a usá-lo para estender todos os outros controllers de sua aplicação. Views E chegamos à camada apresentacional do paradigma MVC: as Views. Uma view é, geralmente, um arquivo HTML com pouca ou nenhuma programação que serve para exibir na tela o conteúdo que você desejar para uma action. Enquanto dentro de um controller você desenvolve toda a lógica de programação do seu sistema, utilizando modelos de acesso a dados e outros componentes, em uma view você determina qual conteúdo será exibido em uma determinada action. No geral, pouco código PHP é escrito dentro de uma view, apenas as estruturas básicas necessárias para manipular o conteúdo já mastigado que você deve enviar a partir do controller. Existem quatro tipos básicos de views: 1. Views estáticas 2. Views dinâmicas 3. Layouts 4. Elements Views estáticas As views estáticas são o tipo de view mais simples. Uma view estática não recebe nenhum tipo de informação de um controller, logo, você pode criar views estáticas sem precisar criar um controller. Por exemplo, se você quiser criar uma página “Sobre Nós”, que em termos gerais não demanda nenhum tipo de programação, apenas HTML simples, não faz sentido criar um controller SobreNosController. Então, para que você consiga acessar esta página através da URL /sobre-nos/, por exemplo, você deve criar uma pasta sobre-nos no diretório app/views/, e dentro dela criar um arquivo index.phtm. Você pode, seguindo os mesmos princípios de funcionamento dos controllers, criar sub-páginas estáticas. Se você quiser criar uma página no endereço /sobre-nos/equipe, deve criar dentro daquela mesma pasta app/views/sobre-nos o arquivo equipe.phtm. Nota: o que faz uma view ser estática é o fato de não possuir código PHP embutido. Porém, elas seguem exatamente as convenções das views comuns, como a estrutura nos diretórios, extensão de arquivos, etc. Views dinâmicas Ao contrário das views estáticas, as dinâmicas são aquelas onde você utiliza código PHP em meio ao HTML. Desta maneira, torna-se obrigatória a presença de um controller. Como descreve o padrão MVC, a camada Controller é a responsável por manipular dados e pela lógica de programação, apenas passando para a camada View o conteúdo já digerido, pronto para ser apresentado na tela. Por isso, em uma view dinâmica você irá, geralmente, receber apenas variáveis enviadas pelo seu controller contendo strings ou arrays, e tudo o que você precisará utilizar de código PHP dentro delas servirá para imprimir o conteúdo destas variáveis na tela. Desta maneira, em sua view você utiliza apenas estruturas básicas do PHP, como if, for e foreach, apenas com esta lógica de apresentação da página. Manipulando as variáveis enviadas pelo controller Você receberá variáveis vindas do controller de maneira normal, como as variáveis padrão do PHP. Se, por exemplo, você definir uma variável no seu controller, conforme o exemplo: $this->set("fruits", array("lemon","orange","apple","grape")); Você então, em sua view, receberá uma variável $fruits, contendo exatamente o mesmo array passado como segundo parâmetro do método set do Controller. Se, por exemplo, quiser transformar este array em uma lista não ordenada, pode utilizar a estrutura de controle foreach, de acordo com o exemplo abaixo: <ul> <?php foreach($fruits as $fruit): ?> <li><?php echo $fruit; ?></li> <?php endforeach; ?> </ul> Layouts Os layouts servem para englobar o conteúdo de uma view – geralmente para adicionar a navegação geral do site, topo, menus e rodapé. Elements Os elements, por sua vez, são views que guardam trechos de código que você utiliza com freqüência em várias partes diferentes de sua aplicação, para que você possa utilizar o mesmo código várias vezes sem ter que reescrevê-lo e sem copiar e colar. Layouts Os layouts fazem parte da camada de View da sua aplicação. Geralmente compõem toda a parte apresentacional que envolve uma view. Em um layout você geralmente inclui sua marca, os menus de navegação, rodapé, entre outros. Os layouts possuem um comportamento bastante semelhante ao das outras views: são arquivos HTML mas, se necessário, você pode usar estruturas simples de PHP, como laços de repetição. Contudo, eles não possuem um controller-pai, pois são compartilhados geralmente entre uma aplicação inteira. O arquivo de layout padrão da sua aplicação Spaghetti* é o arquivo app/layouts/default.phtm, mas você pode criar quantos layouts diferentes você achar necessário. Recebendo o conteúdo de uma view Se você sobrescrever o layout padrão, montando uma estrutura semelhante à seguinte, por exemplo: <html> <head> <title>My Page</title> </head> <body> <h1>Welcome to My Page</h1> </body> </html> Você, no exemplo acima, terá uma página apenas com um cabeçalho “Welcome to My Page”, porém perceberá que o conteúdo da view que você pretendia exibir não aparece neste documento HTML. Acontece que você precisa incluir uma variável convencionada chamada $content_for_layout no local onde você deseja exibir o conteúdo de sua view dentro deste layout, conforme o exemplo que segue: <html> <head> <title>My Page</title> </head> <body> <h1>Welcome to My Page</h1> <?php echo $content_for_layout; ?> </body> </html> No exemplo acima, portanto, além do cabeçalho “Welcome to My Page”, o conteúdo da view solicitada será impresso logo em seguida. Criando layouts e escolhendo qual utilizar Se você possuir uma página de login em seu sistema, provavelmente optará por escrever um layout próprio para esta página, livre dos elementos de navegação presentes em todo o restante do sistema. Para tal, você precisa criar um novo layout na pasta app/layouts/ com o nome do arquivo que você desejar. Então, deve entrar no controller onde deseja alterar o layout, e incluir em seu controller a seguinte atribuição: public $layout = "login"; No exemplo acima, quando alguma action do controller onde a variável $layout foi atribuída for chamada, o Spaghetti* procurará pelo arquivo login.phtm na pasta app/layouts/. Você pode também definir um layout específico para uma action, sem precisar afetar todo as outras actions de um mesmo controller. Para tal, adicione a seguinte atribuição dentro da __action desejada: $this->layout = "login"; Neste caso, apenas a action onde a atribuição acima foi feita é que será afetada pelo layout escolhido, neste caso app/layouts/login.phtm. Alterando o layout padrão da aplicação Conforme dito anteriormente, o layout padrão da sua aplicação é app/layouts/default.phtm. Porém, caso prefira utilizar outro arquivo, pode alterar o layout padrão definindo-o no AppController de sua aplicação, que encontra-se em app/controllers /app_controller.php, adicionando a seguinte atribuição à classe AppController: <?php class AppController extends Controller { public $layout = "login"; } ?> Neste caso, a aplicação toda será afetada e o layout login.phtm. Usando helpers nos layouts Você pode utilizar todos os helpers disponíveis para suas views em seus layouts, contanto que estes helpers tenham sido definidos dentro do controller atual. Para evitar que algum helper não seja incluído por acidente, é uma boa dica carregar os helpers de sua aplicação no AppController, ao invés de carregá-lo em cada controller que criar. Definindo um título para a página Há uma maneira de definir o conteúdo da tag <title> de maneira a não criar código com gambiarras. De modo semelhante à variável $content_for_layout, há uma variável chamada $this->pageTitle, definida dentro de um controller ou action (à sua escolha), onde você pode especificar o conteúdo da tag <title> que será exibido em qualquer lugar do documento HTML. Para exibir o conteúdo da variável $this->pageTitle em seu layout, escreva seu conteúdo dentro da tag <title>, como no exemplo: <title><?php echo $this->pageTitle; ?></title> E para definir o conteúdo da variável $this->pageTitle, faça uma atribuição normal dentro do controller ou action desejado, como nos respectivos exemplos que seguem: public $pageTitle = "Page Title Goes Here"; $this->pageTitle = "Page Title Goes Here"; Elements Por muitas vezes você ocupa pequenos trechos de código em várias páginas, porém estes trechos não fazem parte de um layout. Não se repita, utilize elements. Elementos são views que servem apenas nestas ocasiões. Quer um exemplo? Você pode ter um formulário de login ao topo da página e um no meio do conteúdo. Vai copiar e colar código? E quando for necessário fazer manutenção? É trabalho dobrado para você. Se você criar um element, tudo o que você precisará fazer é escrever o trecho de código uma única vez, e então chamá-lo sempre que necessário. Criando um element A criação é muito simples. Crie um arquivo com o nome desejado para seu element, com a extensão .phtm, logo na pasta app/views/, sem colocar em nenhuma subpasta. No início do nome do arquivo deve constar um caracter underscore (_), para sinalizar que aquele arquivo é um element. Veja o exemplo abaixo: app/views/_formulario_de_login.phtm Quando você quiser incluir o conteúdo deste element em alguma outra view, seja ela estática, dinâmica ou um layout, basta utilizar o método $this->element(), passando como parâmetro o nome do elemento sem o underscore nem a extensão do arquivo: <?php echo $this->element("formulario_de_login"); ?> E pronto. O conteúdo do elemento será renderizado tantas vezes quanto for chamado, e nos lugares onde for chamado. Passando parâmetros para elements Hora ou outra você pode precisar passar conteúdo dinâmico para um element. Por exemplo, você pode criar um element para armazenar um elemento <select> com a lista dos estados nacionais. Este elemento de formulário seria utilizado em diferentes formulários no seu site. Porém, você pode querer passar para este campo de formulário qual é o estado que deve estar selecionado, baseado no estado onde o usuário logado mora. Sem elements, além de manter diversos formulários por todo o site, você teria que reescrever código e a cada manutenção, bom, você já sabe. Para passar variáveis para um element, ao usar o método $this->element() você pode passar como segundo parâmetro um array, onde a chave de um item é o nome da variável e seu valor é o conteúdo da variável, como no exemplo: $options = array( "selectedState" => "SP" ); echo $this->element("formulario_dos_estados", $options); E então, dentro do element você possui condições de manipular esta variável, chamando-a pelo nome. <?php echo $selectedState; ?> Elements são um instrumento bastante interessante de manter o código reaproveitável e de mais fácil manutenção. Use sem moderação ;D Helpers Helpers são classes semelhante aos componentes, porém são exclusivas para as views e para a lógica presentacional compartilhada entre views, layouts e elements. Nestas classes você encontra funções que tornam o seu desenvolvimento client-side mais rápido e fácil. Dois helpers vêm habilitados por padrão na instalação do Spaghetti*: um para HTML e outro para formulários. Utilizando os helpers Conforme dito acima, você só poderá usar as funções de um helper dentro de uma view, layout ou element. Para mais informações sobre como utilizar cada helper, consulte as documentações específicas ao lado. Criando seu próprio helper Para criar um helper, crie um arquivo nome_do_helper_helper.php na pasta app/helpers/. Por exemplo, se fôssemos criar um helper chamado Number, ele seria o arquivo app/helpers /number_helper.php, e dentro dele haveria a classe NumberHelper que estende a classe Helper. Como os helpers são específicos para as views, você não conseguirá ter acesso a modelos de dados de dentro deles. Carregando um helper Você precisa então chamar este helper no controller onde você pretende usá-lo. Caso queira usar um helper com toda a aplicação, carregue-o dentro do AppController, localizado em app/controllers /app_controller.php, adicionando a seguinte variável de instância à classe: public $helpers = array("Number"); Continuando no exemplo, neste caso carregaríamos no controller o helper Number. Porém é importante ressaltar que, definindo o array com apenas Number, os outro helpers embutidos no Spaghetti* não serão mais carregados, pois você está sobrescrendo a chamada padrão. Para continuar a carregar os helpers padrão do Spaghetti, adicione a variável de classe desta maneira: public $helpers = array("Html", "Form", "Number"); Agora seu helper já está pronto para ser usado nas views do seu controller (ou da aplicação inteira, caso tenha incluído o helper no AppController). Usando o helper na view Se o seu helper se chamar Number, logo ele estará acessível em uma view através da variável $number, como no exemplo abaixo: <h1>My Blog</h1> <?php echo $number->ceil(2.0324); ?> A chamada acima procurará pelo helper Number e pelo seu método ceil(), que pode ser escrito assim: <?php class NumberHelper extends Helper { public function ceil($number = null) { $numeroArredondado = ceil($number); $this->output($numeroArredondado); } } ?> Repare que para passar a saída da função você utiliza o método $this->output() passando como parâmetro o conteúdo que você deseja retornar. HTML Helper O helper HTML agiliza a criação de alguns dos elementos que mais tomam tempo, como os chamados para CSS e JavaScript, criação de links a e inserção de imagens img. O helper HTML vem carregado por padrão na sua aplicação Spaghetti*, e portanto é acessível de qualquer view utilizando a variável $html. Inserindo links para outras páginas $html->link( string $value, string $url, array $attributes ) string $value string $url array $attributes String contendo o conteúdo do link String contendo a URL do link Array contendo atributos do elemento a Para gerar links internos basta escrever a URL iniciando pela barra (/), passando esta URL normalmente como segundo parâmetro do método $html->link(). O helper gerará o endereço completo para você. <?php echo $html->link("Adicionar Recado", "/recados/ adicionar"); ?> // Gerará o seguinte: // <a href="/recados/adicionar">Recados</a> Criando links para páginas externas Para gerar links externos basta escrever a URL normalmente como segundo parâmetro do método $html->link(): <?php echo $html->link("Google", "http://www.google.com .br"); ?> // Gerará o seguinte: // <a href="http://www.google.com.br">Google</a> Passando atributos para o elemento a Você pode definir todos os atributos disponíveis passando-os como itens de array no terceiro parâmetro do método $html->link(): <?php echo $html->link("Google", "http://www.google.com .br", array("class"=>"google-link")); ?> // Gerará o seguinte: // <a href="http://www.google.com.br" class="google-link" >Google</a> Criando links em imagens Além disso, se quiser gerar um link em uma imagem, pode também utilizar o método $html->image() do helper HTML para gerar a tag img, conforme o exemplo abaixo: <?php echo $html->link( $html->image("btadicionar.gif", "Adicionar Recado") , "/recados/adicionar"); ?> // Gerará o seguinte: // <a href="/recados/adicionar"><img src=/images/botao_ adicionar.gif" alt="Adicionar Recado" /></a> Criando links com URLs completas Por fim, caso precise gerar URL’s completas em seus links, defina o quarto parâmetro do método $html->link() como true. <?php echo $html->link("Apagar Página", "/paginas/apagar" , array(), true); ?> // Gerará o seguinte: // <a href="http://suaapp.com/pagina/apagar">Apagar</a> Inserindo imagens na sua página $html->image( string $url, string $alt, array $attributes ) string $url string $alt array $attributes String contendo a URL da imagem String contendo o texto do atributo alt (conteúdo alternativo) da imagem Array contendo atributos do elemento img 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 array $attributes boolean $full String contendo a URL do arquivo CSS ou Array, caso sejam várias folhas de estilo Array contendo atributos do elemento style Se true, passa a URL inteira como atributo href O seguinte exemplo gerará um elemento style chamando um arquivo CSS. <?php echo $html->stylesheet("default.css"); ?> // Gerará o seguinte: // <link href="/styles/default.css" rel="stylesheet" type="text/css" /> Nota: O diretório base dos arquivos CSS é app/webroot/styles/, então quando você utilizar o helper HTML para incluir seus arquivos CSS, a URL da folha de estilos deve ser relativa a este diretório. Inserindo estilos hospedados em um servidor externo Para incluir um CSS hospedado em outro servidor, apenas informe a URL completa, como no exemplo que segue: <?php echo $html->stylesheet("http://www.google.com/ default.css"); ?> // Gerará o seguinte: // <link href="http://www.google.com/default.css" rel= "stylesheet" type="text/css" /> Inserindo múltiplos estilos de uma vez Seguindo os princípios de DRY, passar uma nova instrução nova para cada folha de estilo a ser inserida é desperdício de tempo. Por isso, se você precisar incluir várias folhas de estilo, pode passar um array de URLs como primeiro parâmetro do método $html->stylesheet(), como no exemplo abaixo: <?php echo $html->stylesheet(array("default.css", "home.css" ,"form.css")); ?> // Gerará o seguinte: // <link href="/styles/default.css" rel="stylesheet" type="text/css" /> // <link href="/styles/home.css" rel="stylesheet" type= "text/css" /> // <link href="/styles/form.css" rel="stylesheet" type= "text/css" /> Passando atributos para a tag style Se você precisar passar parâmetros para a tag style, pode fazê-lo passando um array de argumentos como segundo parâmetro do método $html->stylesheet(), seguindo o exemplo abaixo: <?php echo $html->stylesheet("default.css", array( "media"=>"handheld")); ?> // Gerará o seguinte: // <link href="/styles/default.css" rel="stylesheet" type="text/css" media="handheld" /> Chamando folhas de estilo com URLs completas Por fim, caso precise gerar URL’s completas em suas tags style, defina o terceiro parâmetro do método $html->stylesheet() como true. <?php echo $html->stylesheet("default.css", array(), true ); ?> // Gerará o seguinte: // <link href="http://suaapp.com/styles/default.css" rel="stylesheet" type="text/css" /> Inserindo arquivos JavaScript na página $html->script(mixed $src, array $attributes, array $full ) mixed $url array $attributes boolean $full String contendo a URL do arquivo Javascript ou Array, caso sejam vários arquivos Array contendo atributos do elemento script Se true, passa a URL inteira como atributo src O seguinte trecho de código gerará um elemento script chamando um arquivo .js. <?php echo $html->script("default.js"); ?> // Gerará o seguinte: // <script src="/scripts/default.js" type="text/javascript"></script> Nota: O diretório base dos arquivos JavaScript é app/webroot /scripts/, então quando você utilizar o helper HTML para incluir seus arquivos JavaScript, a URL do arquivo deve ser relativa a este diretório. Inserindo arquivos de script hospedados em um servidor externo Para incluir um arquivo JavaScript hospedado em outro servidor, apenas informe a URL completa, como no exemplo que segue: <?php echo $html->script("http://www.google.com/defa ult.js"); ?> // Gerará o seguinte: // <script src="http://www.google.com/default.js" type="text/javascript"></script> Inserindo múltiplos arquivos JavaScript de uma vez Seguindo os princípios de DRY, passar uma nova instrução nova para cada arquivo de script a ser inserido é desperdício de tempo. Por isso, se você precisar incluir vários arquivosp, pode passar um array de URLs como primeiro parâmetro do método $html->script() como no exemplo abaixo: <?php echo $html->script(array("default.js", "jquery.js")); ?> // Gerará o seguinte: // <script src="/scripts/default.js" type="text/javascript"> </script> // <script src="/scripts/jquery.js" type="text/javascript"> </script> Passando atributos para a tag script Se você precisar passar parâmetros para a tag script, pode fazê-lo passando um array de argumentos como segundo parâmetro do método $html->script( seguindo o exemplo abaixo: <?php echo $html->script("default.js", array("defer" => "defer")); ?> // Gerará o seguinte: // <script src="/scripts/default.js" type="text/javascript" defer="defer"></script> Chamando arquivos de script com URLs completas Por fim, caso precise gerar URL’s completas em suas tags script, defina o terceiro parâmetro do método $html->script() como 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 array $attributes String opcional indicando a URL de ação do formulário Array opcional de atributos da tag form Se você utilizar o método $form->create() sem passar qualquer parâmetro, a tag padrão será criada, apontando a ação para a URL atual. <?php echo $form->create(); ?> // Gerará o seguinte: // <form action="http://suaapp.com/url_atual_da_pagina" method="post"> Especificando uma URL de ação para o formulário Para especificar a URL para onde o formulário deverá ser enviado, você precisa apenas passar esta URL como primeiro parâmetro do método $form->create(). <?php echo $form->create("http://suaapp.com/enviar"); ?> // Gerará o seguinte: // <form action="http://suaapp.com/enviar" method="post"> Passando outros atributos para a tag form Caso você ainda precise passar outros atributos para a tag de abertura do formulário, como por exemplo alterar o método de envio de POST para GET, pode fazê-lo passando um array de argumentos como segundo parâmetro do método $form->create(). <?php echo $form->create(null, array("method"=>"get")); ?> // Gerará o seguinte: // <form action="http://suaapp.com/url_atual_da_pagina" method="get"> Adicionando campos ao seu formulário Você pode criar todas as tags de um formulário utilizando o método $form->input(), seguindo a seqüência de parâmetros abaixo. Você pode passar, no parâmetro $options, um array contendo todos os atributos disponíveis para o elemento em questão. $form->input( string $name, string $value, array $options ) string $name string $value array $options Nome do campo de formulário que você deseja criar Valor opcional do campo de formulário Array de opções e atributos do campo Criando campos de texto (text) <?php echo $form->input("nome", "João da Silva", array( "type"=>"text", "id"=>"seuNome")); ?> // Gerará o seguinte: // <input type="text" name="nome" value="João da Silva" id="seuNome" /> Criando caixas de texto (textarea) <?php echo $form->input("biografia", "Nasci em São Paulo." , array("type"=>"textarea", "id"=>"suaBiografia")); ?> // Gerará o seguinte: // <textarea name="nome" id="suaBiografia">Nasci em São Paulo.</ textarea> Criando campos de senha (password) <?php echo $form->input("senha", null, array("type"=> "password", "id"=>"suaSenha")); ?> // Gerará o seguinte: // <input type="password" name="senha" id="suaSenha" /> Criando caixas de seleção (select) <?php echo $form->input("estado", "rj", array("type"=> "select", "options" => array("rj"=>"Rio de Janeiro", "sp" => "São Paulo") )); ?> // Gerará o seguinte: // <select name="estado"> // <option name="rj" selected="selected">Rio</option> // <option name="sp">São Paulo</option> // </select> Nota: Neste caso, você passa como segundo parâmetro do método $form->input() a chave do campo que deve estar selecionado por padrão dentro do select. Criando campos de arquivo (file) <?php echo $form->input("foto", null, array("type"=>"file") ); ?> // Gerará o seguinte: // <input type="file" name="foto" /> Nota: Sempre que você for fazer upload de arquivos, deve acrescentar à tag de abertura do formulário o atributo enctype com o valor multipart/form-data. Finalizando e enviando o formulário Você geralmente coloca seu botão de envio de formulários logo antes do término do mesmo. Por esse motivo, você pode usar o mesmo método de encerramento do formulário para gerar – de maneira fácil – o botão de envio. $form->close( string $buttonValue, array $attributes ) string $buttonValue array $attributes Nome do botão de envio, caso você queira utilizá-lo Array de atributos do botão de envio Passando apenas o método, sem qualquer parâmetro, você apenas encerra o formulário com a tag </code>. <?php echo $form->close(); ?> // Gerará o seguinte: // </form> Agora, passando também um parâmetro, você gerará um input button antes do encerramento do formulário. <?php echo $form->close("Enviar"); ?> // Gerará o seguinte: // <input type="submit" name="Enviar" /> // </form> Se você ainda precisar de outros atributos em seu botão, pode passar como segundo parâmetro do método $form->close() um array contendo estes atributos. <?php echo $form->close("Enviar", array( "id"=>"submitButton")); ?> // Gerará o seguinte: // <input type="submit" name="Enviar" id="submitButton" /> // </form> Criando labels para os campos É importante rotular seus campos, e usando o elemento label você torna esta rotulagem ainda mais semântica. Você não precisa chamar métodos adicionais para rotular um campo, apenas deve incluir um atributo no array de atributos do elemento que você deseja rotular. <?php echo $form->input("company", null, array( "type"=>"text", "id"=>"myCompany", "label"=>"Sua Empresa")); ?> // // // // Gerará o seguinte: <label for="myCompany">Sua Empresa <input type="text" name="company" id="myCompany" /> </label> Components Você já viu essa história antes: você começa um projeto, programa uma solução, começa um novo projeto, programa novamente a mesma solução. Components são extensões auto-suficientes, plug and play, para que você não se incomode mais com tarefas repetitivas. Os exemplos mais clássicos incluem envio de e-mails, upload de arquivos e autenticação de usuários. Estamos sempre desenvolvendo novos componentes para nossos próprios problemas, e então compartilhamos eles aqui. Instalando um componente Não há segredos quanto a instalação de um novo componente em sua aplicação. Quando você baixa um componente, extraia o arquivo ZIP e copie o arquivo PHP para a pasta app/components/. E é isso. Já está instalado. Um componente, entretanto, embora esteja instalado não é ativado por padrão. Isso quer dizer que você precisa informar quando deseja usar um componente dentro de um controlador. Para tal, adicione a variável de instância em seu controller conforme o exemplo abaixo: public $components = array("NomeDoComponente"); Você pode ainda carregar vários componentes dentro de um controller passando vários itens dentro do array: public $components = array("NomeDoComponente1", "Nome do Componente2"); Utilizando o componente Vamos supor que você tenha carregado um componente chamado Upload em seu controlador Fotos. Para que você tenha acesso às funcionalidades dentro do controller Fotos, a instância do objeto Upload fica gravada em $this->UploadComponent. Por exemplo, caso você precise utilizar o método upload() deste componente, você o faria dentro de uma action da seguinte maneira: $this->UploadComponent->upload() Nota: Lembre-se sempre que cada componente possui seus próprios métodos e próprio funcionamento. O exemplo acima meramente ilustra como carregar, instanciar e utilizar os métodos de um componente. Escrevendo seus próprios componentes Um componente basicamente é composto por uma classe, chamada de NomeDoComponenteComponent, que estende a classe Component. O arquivo deve ser chamado, neste exemplo, nome_do_componente_component.php, e deve estar na pasta de componentes da sua aplicação em app/components/. Um objeto da classe do seu componente será instanciado automaticamente sempre que um controller solicitar. Por tanto, pelo fato de se tratar de um processo automático, não há como passar parâmetros para o construtor de sua classe. Isso significa que, se você precisar atribuir valores às variáveis de instância, deve fazê-lo dentro do controlador, conforme o exemplo: $person = $this->PersonComponent; $person->name = "Roberto"; $person->age = 32; AuthComponent A autenticação de usuários é algo comum a maioria das aplicações hoje em dia. Pensando nisso, o Spaghetti* já traz o componente AuthComponent em seu núcleo, pronto para ser usado! O uso do AuthComponent é extremamente simples, e sua configuração requer apenas algumas linhas. Em poucos minutos você já tem um sistema de autenticação de usuários simples funcionando. Para usar o AuthComponent, primeiro é preciso ativá-lo nos controllers em que você deseja usá-lo. Como geralmente a autenticação se aplica a vários controllers dentro da aplicação, é recomendável definí-lo diretamente no AppController. class AppController extends Controller { public $components = array("Auth"); } Assim que o componente é ativado, ele se torna disponível dentro do controller através de $this->AuthComponent. Assim, podemos começar a utilizar seus métodos. Criando o modelo de usuários O AuthComponent já espera que você possua um modelo Users, e sua respectiva tabela com, no mínimo, os campos username e password. Caso seja necessário mudar essas opções, você precisa definir isso dentro do controller, no callback beforeFilter(). class AppController extends Controller { public $components = array("Auth"); public function beforeFilter() { // definindo o modelo de usuários $this->AuthComponent->userModel = "AppUsers"; // definindo os campos de nome de usuário e senha $this->AuthComponent->fields = array( "username" => "name", "password" => "passphrase" ); } } Ações de Login e Logout Para que possamos fazer a autenticação do usuário, é necessário criarmos as actions para login e logout. AuthComponent, por padrão, redireciona o usuário para /users/login e /users/logout. Então, em um controller Users, devemos criar essas duas ações. class UsersController extends AppController { public function login() { $this->AuthComponent->login(); } public function logout() { $this->AuthComponent->logout(); } } Assim que essas duas ações são chamadas, é necessário disparar os métodos da classe AuthComponent, login() e logout(). São essas duas funções que farão a verificação, autenticação e desautenticação do usuário. Embora essas funções cuidem da parte difícil, você ainda precisa criar a view de login. <?php echo $form->create(); ?> <?php echo $form->input("username"); // deve ser o mesmo nome definido em // AuthComponent::fields["username"] ?> <?php echo $form->input("password"); // deve ser o mesmo nome definido em // AuthComponent::fields["password"] ?> <?php echo $form->close("Entrar"); ?> Checando o usuário e permitindo acesso Para que possamos checar se o usuário está autenticado, precisamos adicionar uma chamada ao método AuthComponent::check() no callback beforeFilter() do controller. Esse método checa se o usuário está autenticado, e faz o redirecionamento para a tela de login, quando necessário. public function beforeFilter() { $this->AuthComponent->check(); } Mesmo assim, o usuário ainda tem acesso a todos os recursos da aplicação, por padrão o componente permite acesso a toda a aplicação. As permissões podem ser definidas aos níveis de prefixo, controller e action, e são definidas através dos métodos allow e deny. public function beforeFilter() { $this->AuthComponent->check(); $this->AuthComponent->deny("*"); // nega acesso a toda página que não possuir um prefixo $this->AuthComponent->allow(array("controller" => "users", "action" => "register")); $this->AuthComponent->allow(array("prefix" => "public")); } Às vezes, também é preciso verificar se um usuário está aprovado para efetuar login, ou se ele pertence a determinado grupo de usuários. Nesse caso, usa-se o atributo userScope, que provê condições adicionais para a verificação. public function beforeFilter() { $this->AuthComponent->check(); $this->AuthComponent->deny("*"); $this->AuthComponent->userScope = array("approved" => true, "group <>" => "banned"); } Recuperando dados do usuário Dentro da aplicação, também pode se fazer necessária a recuperação de dados do usuário, para poder usá-los na identificação de registros. Sempre que for necessária a utilização de alguma informação do usuário na aplicação, usa-se o método AuthComponent::user(), passando como parâmetro o campo que se deseja retornar. $this->AuthComponent->user("id"); // retornará o id do usuário Encriptando Senhas Não é seguro, e nem considerado uma boa prática, manter as senhas dos usuários sem nenhum tipo de criptografia. O AuthComponent usa hashes MD5, que são um tipo de criptografia de apenas uma via, para armazenar senhas. Isso significa que uma vez que uma senha for criptografada, não há maneira de convertê-la de volta, apenas criar uma nova senha. Assim, toda senha em seu banco de dados deve seguir esse padrão. Para que você não precise usar diretamente a função md5(), o AuthComponent já possui o método hashPasswords(). Ele recebe um parâmetro provindo de Controller::data, e criptografa o campo definido como campo de senha por AuthComponent->fields["password"]. Variáveis para personalização Caso alguma das configurações padrão do AuthComponent seja diferente das suas necessidades, é possível personalizá-lo de forma que lhe atenda melhor. As variáveis configuráveis são: Variável loginAction loginRedirect Função URL para a qual o usuário será redirecionado quando não estiver autenticado 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 fim 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 ficaremos ainda mais contentes se você utilizar o Spaghetti* em algum projeto. A partir de agora, se você tiver interesse, pode continuar acompanhando a evolução e as novidades que virão através do site, http://spaghettiphp.org. Lá você sempre encontrará a documentação mais atual, screencasts, tutoriais e o Trac - onde está o repositório de versões de todo o código escrito para o projeto. Saúde e prosperidade para você e sua equipe, e divirta-se com Spaghetti*! Publicado em 1 de janeiro de 2009 E-mail de contato: [email protected] 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.
Copyright © 2024 DOKUMEN.SITE Inc.