2km Workshop: Desenvolvimento ágil com o CakePHP

Preview:

DESCRIPTION

Slides do primeiro workshop gratuito da 2km interativa! sobre desenvolvimento ágil com o framework CakePHP.

Citation preview

Uma introdução ao framework CakePHP e suas contribuições para o desenvolvimento ágil.

Workshop 1: Desenvolvimento ágil com o CakePHP

Agenda

  Apresentação   Motivação   Desenvolvimento ágil   Princípios de desenvolvimento ágil   Recursos ágeis do CakePHP   O padrão MVC   O padrão ORM   Validações   Aplicação exemplo (Ajax blog)   Como aproveitar melhor tudo isso?   Agradecimentos

Agenda

Apresentação

  A 2km é uma empresa mineira especializada no desenvolvimento ágil de soluções para web utilizando software livre.

  +20 projetos utilizando o CakePHP nos últimos 12 meses.

  Desenvolveu projetos para empresas e organizações como Record Minas, PMDB-MG, Orca veículos entre outras.

Apresentação

  Carlos Pires (Cadu) é bacharel em ciência da computação. Desenvolve e é apaixonado pela web e por software livre desde 1999. Trabalhou com Java(JEE) por mais de 6 anos em diversas empresas da capital mineira. Ultimamente tem se dedicado ao CakePHP e à jQuery. Quando não está andando de bike, está estudando línguas (inglês e espanhol), curtindo um samba de raíz ou tomando uma cervejinha com os amigos.

  Daniel Golgher é tecnólogo em Processamento de Dados, Bacharel em Sistema de Informação e Especialista em Engenharia de Software. Desenvolve em PHP desde 2001. Gosta de software livre, especialmente dos projetos: CakePHP, FreeBSD, MySQL, Apache, PHP, Python dentre outros. Nas horas vagas vai ao cinema com a namorada e passeia com o Baco (São Bernardo).

Agenda

Motivação

  Divulgar o framework CakePHP   Divulgar os novos cursos da 2km   Retribuir à comunidade de software livre   Combater o código 'espaguete'   Mostrar que programar pode ser divertido!

Agenda

Desenvolvimento ágil

  Estórias de usuário   Programação em Pares   Programação orientada ao teste (TDD)   Refatoração (Refactoring)   Reunião em pé (Stand up meeting)   Sprints

Agenda

Princípios do desenvolvimento ágil

  COC – Convention Over Con!guration   DRY - Don't Repeat Yourself   KISS - Keep It Short and Simple or Keep It Simple Stupid   SoC - Separation of Concerns   YAGNI - You Ain't Gonna Need It

Agenda

Recursos ágeis do CakePHP

  MVC [CoC e SoC]   ORM [CoC]   Validação [DRY e KISS]   Testes unitários (SimpleTest) [TDD]   Helpers, Components e Behaviors [DRY]   Geração de código (Bake) [Productivity]

Agenda

Código espaguete?

Fonte: http://desciclo.pedia.ws/wiki/PHP

<div style='display:<?=$valor?$tipo1:$tipo2; ?>'><? if($flag == 0){ ?><script> var a = [<?=implode(',',$lista)?>]; <? $SQL = "SELECT * FROM clientes WHERE 1 ORDER BY data ASC LIMIT 1 OFFSET 1 " ?><? }else{ ?><b> entroh aqui flag= <?=$flag //debugue ?> </b> <? $SQL = "SELECT * FROM clientes WHERE ".$cond." ORDER BY data ASC LIMIT 1 OFFSET ".$flag ?><script> // var a= [<?=implode(',',$lista_)?>];<? } ?> // debugue alert(a);

<<?php echo '/'."script"; // kuIDaDeNHo c/AxXx bAhRRaxXXxx ?>>

</div>

Código MVC

<?php//Arquivo da Classe de Modeloclass Usuario extends AppModel {

var $name = 'Usuario';var $displayField = 'nome';

}?>

<?php//Arquivo da Classe de Controleclass UsuariosController extends AppController {

function teste($grupo_id=null){ $usuarios=$this->Usuario->find('list',array('conditions'=>array('grupo_id'=>$grupo_id))); $this->set(compact('usuarios'));}

}?>

<?php//Arquivo da Classe de Visão$form->create('Usuario',array('action'=>'teste'));$form->input('usuario');$form->end('Enviar');?>

models/usuario.php

controllers/usuarios_controller.php

views/usuarios/teste.ctp

Código em uma camada?

<?php$conn = mysql_connect('localhost','root','senha');mysql_select_db('meu_banco',$conn);$query = 'SELECT id,nome FROM usuarios WHERE grupo="'.$_POST['grupo_id'].'"';$result = mysql_query($query);?><html>

<head>...</head><body> <form action="teste.php"> Selecione o usuário: <select name='usuario'> <?php while($row = mysql_fetch_row($result)){ echo"<option id=".$row[0].">".$row[1]."</option>"; } ?> </select> <input type='submit'> </form></body>

</html>

Exemplo de código em uma camada

Agenda

O padrão ORM

2

1

4

3

Tabelas e relacionamentos

O padrão ORM <?php

class Produto extends AppModel {

var $name="Produto"; var $hasOne = array('Descricao'); var $hasAndBelongsToMany = array('Usuario'); var $belongsTo = array('Categoria' => array( 'className' => 'Categoria', 'foreignKey' => 'categoria_id') ); var $hasMany = array('Comentario' => array( 'className' => 'Comentario', 'foreignKey' => 'comentario_id', 'dependent' => false, 'conditions' => '', 'fields' => '', 'order' => '', 'limit' => ’’ ) );}

?>

1 2

3

4

Classe do modelo Produto com os relacionamentos

Agenda

Validações var $validate = array(

'login' => array('isUnique' => array( 'rule'=>'isUnique', 'message'=>'Este e-mail já existe na base de dados.'), 'email' => array( 'rule' => 'email', 'message' => 'O campo E-mail deve ser um email válido')),'senha' => array( 'rule' => array( 'confirmaSenha', 'senha'), 'message' => 'O campo senha e a confirmação da senha não conferem'),'confirma_senha' => array( 'rule' => 'alphanumeric', 'required' => true, 'message'=>'O campo confirmação da senha é obrigatório', 'on'=>'create'),'nome' => array( 'rule' => array('between', 2, 64), 'message' => 'O campo nome deve possuir de 2 a 64 caracteres') );

function confirmaSenha($data) { return $data ['senha'] == $this->data ['Usuario'] ['confirma_senha']; }

models/usuario.php

Agenda

Aplicação Exemplo: Ajax blog

CREATE TABLE `posts` ( `id` int(10) unsigned NOT NULL auto_increment,

`title` varchar(50) default NULL,`body` text,`created` datetime default NULL,`updated` datetime default NULL,PRIMARY KEY (`id`),KEY `title` (`title`)

) ENGINE=MyISAM DEFAULT CHARSET=latin1

Estrutura da tabela posts da aplicação exemplo

Ajax blog: Con!guração do banco

<?phpclass DATABASE_CONFIG {

var $default = array( 'driver' => 'mysql', 'connect' => 'mysql_connect', 'host' => 'localhost', 'login' => 'root', 'password' => 'passwd', 'database' => 'test', 'prefix' => '' );

}?>

Arquivo de con!guração do banco: con!g/database.php

Ajax blog: Camada de modelo

<?php

class Post extends AppModel {

var $name = 'Post';

}

?>

Classe de modelo da tabela posts: models/post.php

Ajax blog: Camada de controle <?phpclass PostsController extends AppController {

var $name = 'Posts';var $layout = 'ajax_blog';var $helpers = array ('html', 'javascript', 'ajax', 'time' );

function index() { $this->set ( 'data', $this->Post->find ( 'all' ) );}function view($id) { $this->layout = 'ajax'; $this->set ( 'data', $this->Post->read (null,$id) );}function delete($id = null) { if (isset ( $id )) { $id = substr ( $id, 5 ); } $this->Post->del ( $id ); $this->set ( 'data', $this->Post->find ( 'all' ) ); $this->render ( 'list', 'ajax' );}function add() { if (! empty ( $this->data )) { if ($this->Post->save ( $this->data )) { $this->set ( 'data', $this->Post->find ( 'all' ) ); $this->render ( 'list', 'ajax' ); } } else { $this->render ( 'add', 'ajax' ); }}

}?>

Classe de controle dos posts: controllers/posts_controller.php

Ajax blog: Layout padrão

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>CakePHP :: Ajax Blog :: <?php echo $title_for_layout?></title><?php echo $html->charset(); ?><?php echo $javascript->link(array('prototype','scriptaculous','zebra_tables')); ?><?php echo $html->css('css'); ?></head>

<body><div id="container"> <center><h2>Cake Framework AJAX Demo</h2></center>

<div id="content"> <?php echo $content_for_layout?>

</div> <div id="pb-cake"> <a href="http://www.cakephp.org/" class="simple"> <?php echo $html->image('cake.power.png',array( 'width'=>"80", 'height'=>"15", 'alt'=>"CakePHP :: A Rapid Development Framework", 'border'=>"0")); ?> </a> </div></div></body></html>

Layout padrão dos posts: views/layouts/ajax_blog.ctp

Ajax blog: View da index <form action="/posts/search"> <p> <?php echo $html->image('magnify.png', array('alt'=>'Magnify Icon')); ?> <b>Live Search:</b> <input type="text" name="livesearch" id="livesearch" size="40"> <?php echo $html->image('spinner.gif', array('alt'=>'Spinner', 'id'=>'search_spinner', 'style'=>'display:none;')); ?> </p></form><?php echo $ajax->observeField('livesearch', array(

'update'=>'post_table', 'url'=>"/posts/search", 'frequency'=>1,'loading'=>"Element.show('search_spinner');", 'complete'=>"Element.hide('search_spinner');stripe();"));

?><div id="wastebin" class="wastebin"> <center><b>Drag the post's title right here.</b></center> <div> <p id="indicator"> <?php echo $html->image('spinner.gif', array('alt'=>'Indicator')); ?> Deleting ... </p> </div></div><?php echo $ajax->dropRemote('wastebin',

array('accept'=>'title', 'hoverclass'=>'wastebin-active'), array('url'=>'/posts/delete/', 'with'=>'{id:element.id}', 'update'=>'post_table', 'loading'=>'Element.show(\'indicator\')', 'complete'=>'Element.hide(\'indicator\');stripe();' ));

?>...

Layout da view da index: views/posts/index.ctp

Ajax blog: Elemento da listagem dos posts

<td> <div class="title" id="post_<?php echo $post['id'];?>">

<?php echo $html->image('document.gif', array('alt'=>'MagnifyIcon')); ?> <?php echo $post['title']; ?> </div> <?php echo $ajax->drag('post_'.$post['id'], array('revert'=>'true')); ?>

</td> <td><?php echo date("d/m/Y", strtotime($post['created'])) ?> </td> <td> <?php echo $ajax->link('View',"/posts/view/{$post['id']}", array('fallback'=>'#view',

'update'=>"post_content", 'complete'=>"new Effect.Appear('post_content');")) ?>

| <?php echo $ajax->link('Edit', "/posts/edit/{$post['id']}", array('fallback'=>'#edit',

'update'=>"add_post", 'complete'=>"new Effect.Appear('add_post');")) ?>

| <?php echo $ajax->link('Delete', "/posts/delete/{$post['id']}", array('fallback'=>'#list',

'update'=>"post_table", 'complete'=>"stripe();")) ?>

</td>

Elemento da listagem dos posts: views/elements/ajax_posts_lists.ctp

Agenda

Como aproveitar melhor tudo isso?

Fazendo os cursos de desenvolvimento web que a 2km interativa! está lançando:  Curso de CakePHP (Curso mais completo do CakePHP no Brasil - 60 horas)  Curso de jQuery (Abordando as novidades da versão 1.3. Em breve)  Curso de Padrões Web (em breve)

Agenda

Agradecimentos

Agradecemos a presença de todos neste sábado e esperamos vê-los nos próximos workshops!

Dúvidas, críticas, sugestões e doações para:

Carlos Pires (e-mail: carlos.pires@2km.com.br / Twitter: @cadu)

Daniel Golgher (e-mail: daniel@2km.com.br / Twitter: @golgher)

http://www.2km.com.br