Dando continuidade à série sobre artigos do framework symfony, essa semana montarei um CRUD sem utilizar o admin generator. Será criado um sistema de agenda de contatos de telefones.
Tudo será feito de forma manual e vocês verão que não é nenhum bicho de sete cabeças. Qualquer dúvida quanto à instalação, confira o artigo anterior.
Requisitos:
Versão do framework utilizada: 1.0.18 (http://www.symfony-project.org/)
IDE utilizada: Netbeans 6.7 (http://www.netbeans.org)
Siga os procedimentos abaixo:
Crie a pasta onde ficará o projeto:
mkdir imasters
Verifique se o symfony está setado no path (sendo que o /opt/php/bin é onde meu php tá rodando).
No linux:
PATH=$PATH:/opt/php/bin; export PATH
No Windows:
Defina em variáveis de ambiente no campo PATH o caminho do PHP. Exemplo:
C:\\xampplite\\php
Dentro da pasta imasters, criaremos o projeto do symfony (será criada toda a estrutura). Os comandos abaixo são executados no terminal.
symfony init-project imasters
Criar a aplicação frontend:
symfony init-app frontend
O banco de dados que iremos utilizar será o mesmo do artigo anterior.
Abaixo, o SQL para criação do BD e das tabelas.
CREATE SCHEMA IF NOT EXISTS `exemplo01` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;<br />USE `exemplo01`;<br /><br />CREATE TABLE IF NOT EXISTS `exemplo01`.`contato` (<br /> `id` INT NOT NULL AUTO_INCREMENT ,<br /> `nome` VARCHAR(100) NULL ,<br /> PRIMARY KEY (`id`) )<br />ENGINE = InnoDB;<br /><br /><br />CREATE TABLE IF NOT EXISTS `exemplo01`.`tipo` (<br /> `id` INT NOT NULL AUTO_INCREMENT ,<br /> `tipo` VARCHAR(45) NULL ,<br /> PRIMARY KEY (`id`) )<br />ENGINE = InnoDB;<br /><br /><br />CREATE TABLE IF NOT EXISTS `exemplo01`.`telefone` (<br /> `id` INT NOT NULL AUTO_INCREMENT ,<br /> `tipo_id` INT NULL ,<br /> `contato_id` INT NULL ,<br /> `ddd` VARCHAR(2) NULL ,<br /> `fone` VARCHAR(20) NULL ,<br /> PRIMARY KEY (`id`) ,<br /> INDEX `fk_telefone_contato` (`contato_id` ASC) ,<br /> INDEX `fk_telefone_tipo` (`tipo_id` ASC) ,<br /> CONSTRAINT `fk_telefone_contato`<br /> FOREIGN KEY (`contato_id` )<br /> REFERENCES `exemplo01`.`contato` (`id` )<br /> ON DELETE NO ACTION<br /> ON UPDATE NO ACTION,<br /> CONSTRAINT `fk_telefone_tipo`<br /> FOREIGN KEY (`tipo_id` )<br /> REFERENCES `exemplo01`.`tipo` (`id` )<br /> ON DELETE NO ACTION<br /> ON UPDATE NO ACTION)<br />ENGINE = InnoDB;Configure a conexão com o banco de dados nos arquivos: config/databases.yml e config/propel.ini
databases.yml
all:<br /> propel:<br /> class: sfPropelDatabase<br /> param:<br /> phptype: mysql<br /> hostspec: localhost<br /> database: exemplo01<br /> username: root<br /> password: <br /> encoding: utf8<br /> persistent: falsepropel.ini
Configurar as linhas abaixo, onde exemplo01 é o nome do bd que criamos.
propel.database.createUrl = mysql://root@localhost/<br />propel.database.url = mysql://root@localhost/exemplo01Vamos gerar o schema.yml (mapeamento objeto-relacional) e os models:
Para gerar o schema.yml:
symfony propel-build-schema
Para gerar os modelos:
symfony propel-build-model
Criar os módulos:
symfony init-module frontend contato
symfony init-module frontend tipo
symfony init-module frontend telefone
e criar as actions necessárias para o funcionamento da aplicação:
apps/frontend/modules/contato/actions/actions.class.php
class contatoActions extends sfActions {<br /><br /><br /> /**<br /> * Exibe os contatos cadastrados<br /> */<br /> public function executeIndex() {<br /><br /> $c = new Criteria();<br /> $c->addAscendingOrderByColumn(ContatoPeer::NOME);<br /> $this->contatos = ContatoPeer::doSelect($c);<br /> }<br /><br /><br /> /**<br /> * Edita/Novo Contato<br /> */<br /> public function executeEditar() {<br /><br /> if($this->getRequestParameter('id')) {<br /> $this->contato = ContatoPeer::retrieveByPk($this->getRequestParameter('id'));<br /> $this->forward404Unless($this->contato);<br /> $this->acao = 'Editar Contato';<br /> }<br /> else {<br /> $this->contato = new Contato();<br /> $this->acao = 'Novo Contato';<br /> }<br /> }<br /><br /><br /> /**<br /> * Atualiza os dados do contato<br /> */<br /> public function executeAtualizar() {<br /> if($this->getRequestParameter('id')) {<br /> $contato = ContatoPeer::retrieveByPk($this->getRequestParameter('id'));<br /> $this->forward404Unless($contato);<br /> }<br /> else {<br /> $contato = new Contato();<br /> }<br /><br /> $contato->setNome($this->getRequestParameter('nome'));<br /> $contato->save();<br /><br /> $this->forward('contato', 'index');<br /> }<br /><br /><br /> /**<br /> * Exclui um contato<br /> */<br /> public function executeExcluir()<br /> {<br /> $contato = ContatoPeer::retrieveByPk($this->getRequestParameter('id'));<br /> $this->forward404Unless($contato);<br /> $contato->delete();<br /> $this->forward('contato', 'index');<br /> }<br /><br />}apps/frontend/modules/telefone/actions/actions.class.php
class telefoneActions extends sfActions<br />{<br /><br /> /**<br /> * Exibe os telefones cadastrados<br /> */<br /> public function executeIndex() {<br /><br /> $c = new Criteria();<br /> $c->addAscendingOrderByColumn(TelefonePeer::CONTATO_ID);<br /> $c->addAscendingOrderByColumn(TelefonePeer::TIPO_ID);<br /> $this->telefones = TelefonePeer::doSelect($c);<br /><br /> }<br /><br /><br /> /**<br /> * Edita/Novo Telefone<br /> */<br /> public function executeEditar() {<br /><br /> if($this->getRequestParameter('id')) {<br /> $this->telefone = TelefonePeer::retrieveByPk($this->getRequestParameter('id'));<br /> $this->forward404Unless($this->telefone);<br /> $this->acao = 'Editar Telefone';<br /> }<br /> else {<br /> $this->telefone = new Telefone();<br /> $this->acao = 'Novo Telefone';<br /> }<br /><br /> //contatos<br /> $c = new Criteria();<br /> $c->addAscendingOrderByColumn(ContatoPeer::NOME);<br /> $this->contatos = ContatoPeer::doSelect($c);<br /><br /> //tipos<br /> $c = new Criteria();<br /> $c->addAscendingOrderByColumn(TipoPeer::TIPO);<br /> $this->tipos = TipoPeer::doSelect($c);<br /> }<br /><br /><br /> /**<br /> * Atualiza os dados do telefone<br /> */<br /> public function executeAtualizar() {<br /> if($this->getRequestParameter('id')) {<br /> $telefone = TelefonePeer::retrieveByPk($this->getRequestParameter('id'));<br /> $this->forward404Unless($telefone);<br /> }<br /> else {<br /> $telefone = new Telefone();<br /> }<br /><br /> $telefone->setTipoId($this->getRequestParameter('tipo_id'));<br /> $telefone->setContatoId($this->getRequestParameter('contato_id'));<br /> $telefone->setDdd($this->getRequestParameter('ddd'));<br /> $telefone->setFone($this->getRequestParameter('fone'));<br /> $telefone->save();<br /><br /> $this->forward('telefone', 'index');<br /> }<br /><br /><br /> /**<br /> * Exclui um telefone<br /> */<br /> public function executeExcluir() {<br /> $telefone = TelefonePeer::retrieveByPk($this->getRequestParameter('id'));<br /> $this->forward404Unless($telefone);<br /> $telefone->delete();<br /> $this->forward('telefone', 'index');<br /> }<br /><br />}apps/frontend/modules/tipo/actions/actions.class.php
class tipoActions extends sfActions {<br /><br /> /**<br /> * Exibe os tipos cadastrados<br /> */<br /> public function executeIndex() {<br /><br /> $c = new Criteria();<br /> $c->addAscendingOrderByColumn(TipoPeer::TIPO);<br /> $this->tipos = TipoPeer::doSelect($c);<br /> }<br /><br /><br /> /**<br /> * Edita/Novo Tipo<br /> */<br /> public function executeEditar() {<br /><br /> if($this->getRequestParameter('id')) {<br /> $this->tipo = TipoPeer::retrieveByPk($this->getRequestParameter('id'));<br /> $this->forward404Unless($this->tipo);<br /> $this->acao = 'Editar Tipo';<br /> }<br /> else {<br /> $this->tipo = new Tipo();<br /> $this->acao = 'Novo Tipo';<br /> }<br /> }<br /><br /><br /> /**<br /> * Atualiza os dados do tipo<br /> */<br /> public function executeAtualizar() {<br /> if($this->getRequestParameter('id')) {<br /> $tipo = TipoPeer::retrieveByPk($this->getRequestParameter('id'));<br /> $this->forward404Unless($tipo);<br /> }<br /> else {<br /> $tipo = new Tipo();<br /> }<br /><br /> $tipo->setTipo($this->getRequestParameter('tipo'));<br /> $tipo->save();<br /><br /> $this->forward('tipo', 'index');<br /> }<br /><br /><br /> /**<br /> * Exclui um tipo<br /> */<br /> public function executeExcluir() {<br /> $tipo = TipoPeer::retrieveByPk($this->getRequestParameter('id'));<br /> $this->forward404Unless($tipo);<br /> $tipo->delete();<br /> $this->forward('tipo', 'index');<br /> }<br />}Agora vamos criar os templates referentes às actions:
apps/frontend/modules/contato/templates/indexSuccess.php
<?php include_partial('global/menu') ?><br /><br /><?php echo button_to('Novo contato', 'contato/editar') ?><br /><br /><table><br /> <thead><br /> <tr><br /> <td>Id</td><br /> <td>Nome</td><br /> <td>Opções</td><br /> </tr><br /> </thead><br /><br /> <tbody><br /> <?php<br /> if($contatos) { ?><br /> <?php foreach($contatos as $contato) { ?><br /> <tr><br /> <td><?php echo $contato->getId() ?></td><br /> <td><?php echo $contato->getNome() ?></td><br /> <td><?php echo link_to('editar', 'contato/editar?id=' . $contato->getId() ) ?> <br /> <?php echo link_to('excluir', 'contato/excluir?id=' . $contato->getId(), '?confirm=Deseja mesmo excluir?' ) ?></td><br /> </tr><br /> <?php<br /> }<br /> }<br /> else { ?><br /> <tr><br /> <td colspan="3">Nenhum contato cadastrado!</td><br /> </tr><br /> <?php } ?><br /> </tbody><br /></table>apps/frontend/modules/contato/templates/editarSuccess.php
<?php include_partial('global/menu') ?><br /><br /><?php use_helper('Object') ?><br /><br /><?php echo form_tag('contato/atualizar') ?><br /><?php echo object_input_hidden_tag($contato, 'getId') ?><br /><br /><table><br /> <thead><br /> <tr><br /> <td colspan="2"><?php echo $acao ?></td><br /> </tr><br /> </thead><br /><br /> <tbody><br /> <tr><br /> <td>Nome:</td><br /> <td><?php echo object_input_tag($contato, 'getNome') ?></td><br /> </tr><br /><br /> <tr><br /> <td colspan="2"><?php echo submit_tag('Gravar') ?> <br /> <?php echo button_to('Cancelar', 'telefone/index', array('confirm'=>'Deseja mesmo cancelar?')) ?></td><br /> </tr><br /> </tbody><br /></table>apps/frontend/modules/telefone/templates/indexSuccess.php
<?php include_partial('global/menu') ?><br /><br /><?php echo button_to('Novo telefone', 'telefone/editar') ?><br /><br /><table><br /> <thead><br /> <tr><br /> <td>Id</td><br /> <td>Contato</td><br /> <td>Tipo</td><br /> <td>Fone</td><br /> </tr><br /> </thead><br /><br /> <tbody><br /> <?php<br /> if($telefones) { ?><br /> <?php foreach($telefones as $telefone) { ?><br /> <tr><br /> <td><?php echo $telefone->getId() ?></td><br /> <td><?php echo $telefone->getContato()->getNome() ?></td><br /> <td><?php echo $telefone->getTipo()->getTipo() ?></td><br /> <td><?php echo link_to('editar', 'telefone/editar?id=' . $telefone->getId() ) ?> <br /> <?php echo link_to('excluir', 'telefone/excluir?id=' . $telefone->getId(), '?confirm=Deseja mesmo excluir?' ) ?></td><br /> </tr><br /> <?php<br /> }<br /> }<br /> else { ?><br /> <tr><br /> <td colspan="4">Nenhum telefone cadastrado!</td><br /> </tr><br /> <?php } ?><br /> </tbody><br /></table>apps/frontend/modules/telefone/templates/editarSuccess.php
<?php include_partial('global/menu') ?><br /><br /><?php use_helper('Object') ?><br /><br /><?php echo form_tag('telefone/atualizar') ?><br /><?php echo object_input_hidden_tag($telefone, 'getId') ?><br /><br /><table><br /> <thead><br /> <tr><br /> <td colspan="2"><?php echo $acao ?></td><br /> </tr><br /> </thead><br /><br /> <tbody><br /> <tr><br /> <td>Contato:</td><br /> <td><?php echo select_tag(<br /> 'contato_id',<br /> objects_for_select(<br /> $contatos,<br /> 'getId',<br /> 'getNome',<br /> $telefone->getContatoId(),<br /> 'include_custom=--Selecione--'<br /> )<br /> ) ?></td><br /> </tr><br /><br /> <tr><br /> <td>Tipo:</td><br /> <td><?php echo select_tag(<br /> 'tipo_id',<br /> objects_for_select(<br /> $tipos,<br /> 'getId',<br /> 'getTipo',<br /> $telefone->getTipoId(),<br /> 'include_custom=--Selecione--'<br /> )<br /> ) ?></td><br /> </tr><br /><br /> <tr><br /> <td>DDD:</td><br /> <td><?php echo object_input_tag($telefone, 'getDdd', array('size'=>'2')) ?></td><br /> </tr><br /><br /> <tr><br /> <td>Telefone:</td><br /> <td><?php echo object_input_tag($telefone, 'getFone', array('size'=>'15')) ?></td><br /> </tr><br /><br /> <tr><br /> <td colspan="2"><?php echo submit_tag('Gravar') ?> <br /> <?php echo button_to('Cancelar', 'telefone/index', array('confirm'=>'Deseja mesmo cancelar?')) ?><br /> </td><br /> </tr><br /> </tbody><br /></table>apps/frontend/modules/tipo/templates/indexSuccess.php
<?php include_partial('global/menu') ?><br /><br /><?php echo button_to('Novo tipo', 'tipo/editar') ?><br /><br /><table><br /> <thead><br /> <tr><br /> <td>Id</td><br /> <td>Tipo</td><br /> <td>Opções</td><br /> </tr><br /> </thead><br /><br /> <tbody><br /> <?php<br /> if($tipos) { ?><br /> <?php foreach($tipos as $tipo) { ?><br /> <tr><br /> <td><?php echo $tipo->getId() ?></td><br /> <td><?php echo $tipo->getTipo() ?></td><br /> <td><?php echo link_to('editar', 'tipo/editar?id=' . $tipo->getId() ) ?> <br /> <?php echo link_to('excluir', 'tipo/excluir?id=' . $tipo->getId(), '?confirm=Deseja mesmo excluir?' ) ?></td><br /> </tr><br /> <?php<br /> }<br /> }<br /> else { ?><br /> <tr><br /> <td colspan="3">Nenhum tipo cadastrado!</td><br /> </tr><br /> <?php } ?><br /> </tbody><br /></table>apps/frontend/modules/tipo/templates/editarSuccess.php
<?php include_partial('global/menu') ?><br /><br /><?php use_helper('Object') ?><br /><br /><?php echo form_tag('tipo/atualizar') ?><br /><?php echo object_input_hidden_tag($tipo, 'getId') ?><br /><br /><table><br /> <thead><br /> <tr><br /> <td colspan="2"><?php echo $acao ?></td><br /> </tr><br /> </thead><br /><br /> <tbody><br /> <tr><br /> <td>Nome:</td><br /> <td><?php echo object_input_tag($tipo, 'getTipo') ?></td><br /> </tr><br /><br /> <tr><br /> <td colspan="2"><?php echo submit_tag('Gravar') ?> <br /> <?php echo button_to('Cancelar', 'tipo/index', array('confirm'=>'Deseja mesmo cancelar?')) ?></td><br /> </tr><br /> </tbody><br /></table>apps/frontend/templates/_menu.php
<div id="menu"><br /><ul><br /> <li><span><?php echo link_to('Contato', 'contato/index') ?></span></li><br /> <li><span><?php echo link_to('Tipo', 'tipo/index') ?></span></li><br /> <li><span><?php echo link_to('Telefone', 'telefone/index') ?></span></li><br /></ul><br /></div>Alterar em apps/frontend/config/routing.yml a action que será executada em primeira instância.
homepage:<br /> url: /<br /> param: { module: default, action: index }mudar para:
homepage:<br /> url: /<br /> param: { module: contato, action: index }Criei um arquivo chamado _menu.php que será o menu do sistema e será incluído em todas as páginas. Nos templates, para efetuar a inclusão utilizaremos o include_partial(). Os partials são pedaços de códigos reutilizáveis, são armazenados na pasta templates/. Um arquivo partial SEMPRE começa com sublinhado (_), isso ajuda a distiguir os arquivos, já que eles ficam no mesmo diretório. Ele pode ser incluído no mesmo módulo, em outro módulo, ou no diretório global templates/.
Edite o arquivo apps/frontend/config.yml para alterar os dados do projeto como title, description e keywords. No caso do nosso projeto, deixei da seguinte maneira:
de:
metas:<br /> title: symfony project<br /> robots: index, follow<br /> description: symfony project<br /> keywords: symfony, project<br /> language: enpara:
metas:<br /> title: Crud Symfony - iMasters<br /> robots: index, follow<br /> description: Exemplo de criaçao de um crud manual<br /> keywords: crud, symfony, imasters<br /> language: enLimpe o cache do symfony
symfony cc
Vamos abrir o browser e ver como está ficando o nosso “pequeno” sistema. Veja que está sem layout mas está funcional, incluindo, alterando e excluindo os dados.
http://127.0.0.1/imasters/web/frontend_dev.php/
Último passo será mexermos no CSS para criar uma apresentação mais amigável. Abra o arquivo: web/css/main.css
ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,body,html,p,blockquote,fieldset,input<br />{ margin: 0; padding: 0; }<br />a img,:link img,:visited img { border: none; }<br /><br />ol, ul, li {list-style: none;}<br /><br />a<br />{<br /> text-decoration: none;<br />}<br /><br />a:hover<br />{<br /> text-decoration: underline;<br />}<br /><br />body, td<br />{<br /> margin: 0;<br /> padding: 0;<br /> font-family: Arial, Verdana, sans-serif;<br /> font-size: 11px;<br />}<br /><br />body<br />{<br /> padding: 20px;<br />}<br /><br /><br />/*MENU*/<br />#menu{background:#666666;height:24px;}<br />#menu li{float:left;position:relative;}<br />#menu li a { color:#fff;}<br />#menu li span{display:block; font:bold 14px arial;line-height:24px;width:122px; text-align:center; background:#8F8F8F; cursor:pointer;margin-left:10px}<br />#menu li ul{overflow:hidden;position:absolute;z-index:10000;}<br />#menu li ul li{float:none;display:block; font:bold 12px arial;line-height:18px;width:120px; text-align:center; background:#fff; cursor:pointer;margin-left:10px; border:1px solid #CCCCCC; margin-top:2px;}<br />#menu li ul li a{ color:#8F8F8F;}<br /><br />/*TABELAS*/<br />thead tr{background: #A2090C; }<br />thead td{text-align:center;color:#fff;font:bold 11px arial;padding:3px 0;}<br />tbody td{padding:3px;}<br />table {width:100%; margin-top:15px; *border-collapse: collapse;}<br />table .nivel_2{background:#ccc;}<br />table .nivel_2 td{color:#000;text-align:left; padding:3px;}<br />table tbody td{border-bottom:1px solid #ccc;}<br />table tbody td.center{text-align:center}Veja como ficou o sistema após as alterações no CSS:
Lista os contatos.
Novo contato
Novo telefone
Links úteis:
http://www.symfony-project.org/book/1_0/
Download do sistema
Para efetuar o download dos arquivos, clique AQUI
ATENÇÃO
Se for utilizado o arquivo acima, não se esqueça de mudar o arquivo config/config.php que indica o caminho do symfony.
Semana que vem tem mais. Espero que vocês tenham gostado!
Não deixe de nos enviar críticas ou sugestões para o próximo assunto, afinal, a coluna é de vocês.







