CakePHP Brasil

3 outubro 2008

Groups do CakePHP Brasil mudou de endereço

Arquivado em: CakePHP — Tags:, — Juan Basso @ 9:32 pm

Pessoal,

O Gustavo Carreno, dono do Groups cake-php-pt, teve problemas com sua conta do Google e acabou perdendo a autoridade do groups. Agora ele criou um novo groups para o pessoal e pedimos a todos que atualizem seus favoritos. Agora o groups chama-se cakephp-pt (sem o hifen entre o cake e php).

Novo link: http://groups.google.com/group/cakephp-pt

 

Abraços e esperamos vocês lá.

12 setembro 2008

Pensando no CakePHP para SofterHouse’s

Arquivado em: CakePHP — Tags:, , , , , , — Juan Basso @ 9:11 pm

Pessoal,

 

Estava pensando sobre o desenvolvimento de um sistema modular (um ERP, CRM, etc), vendido em partes para o cliente e que o código fosse deixado no cliente (nem que fosse criptografado com as diversas ferramentas que há disponível por aí…). Dai pensei, como fazer isso com o CakePHP?!

Pensando, achei que fosse legal criar cada módulo como um plugin, inclusive alguns recursos básicos do sistema, como a parte de autenticação (login). Deixar a ‘app’ como um barramento da aplicação, fornecendo components, helpers, layouts, css/js, vendors, etc. Essa parte funcionaria como uma infra estrutura do sistema, onde as rotas poderiam ser criadas dinâmicamente pelo AppController do plugin ou usar as rotas diretamente do sistema (plugin/controller/action/params).

Hoje o CakePHP dispões de várias funções para identificar se o app possui um componente ou outro plugin instalado, podendo os plugins “se conversarem”. O comando App::listObjects(’Plugin’), por exemplo é fantástico para saber se um outro módulo também está instalado. Assim não precisaria cadastrar cada módulo numa base de dados, que poderia ser manipulada pelo cliente ou coisa do genero.

O mesmo poderia ser aplicado a uma empresa que possui diversos softwares, não necessariamente inteligados (em módulos). Onde todas as aplicações teriam um ambiente de desenvolvimento comum (barramento) e cada aplicação seria um plugin. Isso reduziria a quantidade de código e, consequentemente, o tamanho da aplicação nos clientes que tiverem mais de uma aplicação.

 

O que acham? Já passaram por algo assim?

11 setembro 2008

Trabalhando com JSON no CakePHP 1.2

Arquivado em: CakePHP, Tutoriais — Tags:, , , , , , — Juan Basso @ 10:13 pm

Com o crescimento do uso de AJAX, da maioria dos frameworks de JavaScript (jQuery, Prototype, mooTools, YUI, ExtJS, …) e de uma dúvida no Groups do Google (Action que renderize apenas o layout, sem necessidade de uma view), resolvi escrever um post falando sobre como usar JSON no CakePHP de forma automática para retorno dos dados, sem precisar gerar um arquivo de view para cada action e que não fere o MVC.
A Solução

Para solucionar o caso, achei que o melhor jeito seria criando uma classe de View nova. A classe View do CakePHP ela sempre procura um arquivo de view, além do template. Com a nova classe, seria feita a renderização ali mesmo, sem a necessidade de novos arquivos.

A classe que criei (JsonView) pode ser baixada aqui. Ela deve ser colocada na pasta views de da sua aplicação (nenhuma sub-pasta) com o nome de json.php. Ou seja, no final, você terá o caminho app/views/json.php.
Como Usar

Para usar é bem simples. No seu controller, quando você for retornar um código em JSON, basta alterar a variável $view do controller para usar a nova classe. Além disso, os dados que você quer que retorne, devem ser setados com o nome ‘json‘ no seu controller. Caso não seja, ele vai renderizar normalmente. Exemplo de uso no controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class UsuariosController extends AppController {
	var $uses = array('Usuario', 'Grupo');
 
	function index($json = false) {
		$this->set('usuarios', $this->Usuario->find('list'));
		if ($json) {
			$this->view = 'Json';
			$this->set('json', 'usuarios');
		}
	}
 
	function multilista($json = false) {
		$this->set('usuarios', $this->Usuario->find('list'));
		$this->set('grupos', $this->Grupo->find('list'));
		if ($json) {
			$this->view = 'Json';
			$this->set('json', array('usuarios', 'grupos'));
		}
	}
}

Neste caso, quando o parâmetro de index não for true, ele vai renderizar como se fosse uma requisição normal. Caso passe como true, ele irá renderizar como JSON. Já no método multilista, além do parâmetro para verificar se é JSON, ele passa um array de variáveis para a view JSON, assim a classe irá renderizar mais de uma variável.

Outra maneira de se fazer é definir a variável $view da classe diretamente com ‘Json’ (assim como foi feito com $uses no exemplo). Assim, sempre que você der um set na variável ‘json’, a classe da View se liga e renderiza em json, caso contrário mantém o normal.

Conclusão

Este é um método fácil e rápido de renderizar as requisições JSON, sem precisar criar um arquivo para cada requisição e sem precisar de muito código (tanto no controller, quanto na view).

O código que fiz, é compatível com PHP 4 e 5, então é possível usar com o CakePHP sem medo em qualquer versão de PHP.

Abraços e bom uso. :) Dicas são sempre bem vindas.

4 setembro 2008

Um “pouco” sobre testes

Arquivado em: CakePHP — Tags: — Juan Basso @ 7:34 pm

No grupo de CakePHP, Cesar Fuentes criou um tópico sobre testes no CakePHP, pedindo sobre o assunto. Vejam a resposta de José Pedrini (autorizado pelo autor para disponibilizar o conteúdo):

 

Vou falar um “pouco” sobre o que eu sei, mas eu recomendo que todos procurem na internet e estudem, pois o assunto é interessante. 

A primeira vantagem de se escrever teste é trivial. Ao invés de ficar fazendo testes manualmente, você escreve programas que testam automaticamente. Testes automatizados criam uma malha protetora, garantindo que seu código faça aquilo que você pensa que ele tem que fazer. Automatizar testes ajudam você testar aquela  aplicação de 5000 linhas em pequeno tempo de execução. 

Bem, como esta técnica notoriamente é vantajosa, os desenvolvedores começaram a usa-la e uns malucos acharam TÃO boa que começaram a testar antes mesmo de escrever código. Dai nasce o TDD[1]. Você não pode testar manualmente alguma coisa que ainda não criou, mas pode programar algo que teste.

Como os programadores buscam sempre o DRY (dont repeat yourself), foram criados vários frameworks e ferramentas para melhorar a forma com que testamos, posso citar os xUnits, a cobertura de testes, gerenciadores de macros, fixtures, etc. São inúmeras ferramentas e, normalmente, cada linguagem possui um grande conjunto delas, portanto não vou me aprofundar nisto.

No CakePHP, o framework de teste utilizado é o SimpleTest[2]. A função de um framework de teste é prover o cenário ideal para se realizar testes. Quem mexe com experimentos sabe a importância de se ter um ambiente apropriado. Um exemplo desta preparação de ambientes são os fixtures. Para fazermos testes é importante sabermos o estado inicial de sua aplicação. Imagine testar a inserção de um comentário em um tópico, no momento de desenvolvimento do teste, você tinha certeza que o tópico existia, mas se no momento de execução do teste ele não existir? Seu teste irá falhar, mas não por que seu programa está corrompido, mas sim por que o estado inicial do teste não estava controlado.

Os principais métodos que usamos no framework são os métodos de Assert, no SimpleTest encontramos diversos[3], eles nos auxiliam a testar vários tipos de situações. É fazendo asserções que vocês irão testar seus códigos. Um exemplo de asserção é: Se eu passar o valor 5 para uma função de fatorial o resultado tem que ser 120. As asserções são feitas na tentativa de explorar seus códigos. Não é interessante fazer 10 asserções testando todos os valores entrado entre 5 e 15. Mas se eu testar alguns valores chaves, que realmente tragam significado, estarei realmente protegendo minha aplicação. No exemplo, alguns testes interessantes são valores negativos, 0 e 1.

Os testes são divididos em 3 grandes áreas (me desculpem se estou falando alguma merda): Unitário, Funcional e de Aceitação. Os de aceitação são aqueles que envolve testes que o seu cliente faria, testes que envolvem a interface, algo que pegue a aplicação inteira. Mesmo existindo ferramentas para estes testes, normalmente não se roda toda hora, eles podem ser custosos. Testes funcionais são aqueles que testam integrações entre objetos e métodos, é quando dois ou mais objetos devem trabalhar juntos. Já os testes unitários testam a lógica local de um objeto, de um método. Não tem muita diferença entre unitário e funcional, somente o conceito.

Bem, é este o conceito por trás dos testes, não sei mais o que eu posso falar. Para dar algo prático, vou tentar falar um pouco de como testar no CakePHP, mas não prometo muita coisa, não tem como falar de tudo.

A primeira coisa que vocês terão que fazer é colocar o SimpleTest na pasta Vendors (seja ela da aplicação ou do cake), assim vocês poderão rodar os testes. A título de experiência, visitem o link http://endereco_aplicacao/test.php. É nesta página que vocês irão executar os seus testes. O CakePHP deixa que você execute os testes do Core (coisa que acredito que não precisava, mas acho que eles deixaram para estimular o pessoal a contribuir com o desenvolvimento). Rodem algum teste (recomento o Views, pois não usa banco de dados). Vocês vão encontrar ou uma barra verde ou uma barra vermelha com os erros que ocorreram. Quando ocorre alguma exceção, algum warning, erro, o que seja, também aparecerá lá.

Agora que sabem como executar os testes, vamos fazer alguns testes. Primeiramente, como tudo no CakePHP, existe uma convenção de nomes de arquivos O padrão do Cake é XXXX.test.php. O XXXX pode ser qualquer coisa, mas é recomendável que seja o nome do arquivo que você quer testar (quando forem fazer cobertura de teste vocês entenderão). Utilizem as pastas predefinidas do CakePHP.

Eu vou utilizar um exemplo aqui sobre um Model de Tópicos, vocês utilizem o que for necessário para sua aplicação. Primeira coisa, vou criar um arquivo chamado topico.test.php na pasta /app/tests/cases/models. E, utilizarei a seguinte estrutura:

1
2
3
4
App::import('Model','Topico');
class TopicoTestCase extends CakeTestCase {
	var $fixtures = array('topico');
}

* Antes de mais nada, eu não utilizo o método que tinha no CookBook do Cake. Eu faço diferente e parece que outras pessoas[4] também não gostaram e já incluiram uma correção no Cake. Como não sei se esta correção está no RC2 ou só no SVN, vou explicar o que é necessário para fazer do meu modo. Peço desculpas, mas não vou explicar o por que disto, pois só iria complicar, mais explicações no [4]. 

Adicionem no app_model.php de sua aplicação a seguinte lógica: * 

1
2
3
4
5
6
function __construct(){
	if(isset($_GET['app'])){
		$this->useDbConfig = 'test'; // Ou nome do seu DataSource de teste (aquele que fica no arquivo database.php)
	}
	parent::__construct();
}

Agora voltando, o código inicial é simples, primeiro estamos incluindo a classe Topico para podermos instancia-la e testa-la. Criamos uma sub-classe de Case do CakeTestCase, assim teremos todo o ambiente necessário para podermos testar. E colocamos uma variável chamada fixtures. PARA! O que é fixtures?

Bem, lembram quando falei de ambiente de testes? de que tínhamos de ter controle do estado inicial de nossos testes? Quem garante isto são os Fixtures. O fixture vai, A CADA teste LIMPAR todo o banco e REPOPULAR com as ENTRADAS especificadas no arquivo de fixtures. Assim, você terá a certeza de que todo inicio de teste você tem um banco limpinho e bunitinho. No meu 
exemplo, o arquivo teria o nome topico_fixture.php e ficaria no /app/tests/fixtures/ : 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class TopicoFixture extends CakeTestFixture {
	var $name = 'Topico';
	var $fields = array(
		'id' => array(
			'type' => 'integer',
			'key'  => 'primary'
		),
		'titulo' => array(
			'type'   => 'string',
			'length' => 200,
		),
		'publicado' => array(
			'type' => 'boolean'
		)
	);
	var $records = array(
		array(
			'id'=>1,
			'titulo'=>'Como escrever um e-mail gigantesco',
			'publicado'=>true
		),
		array(
			'id'=>2,
			'titulo'=>'Como ler um texto antes de escrever?',
			'publicado'=>false
		)
	);
}

Só para explicar, a variável $fields é a estrutura do banco (vocês podem utiliza o shell schema para gerar isto para vocês[5]) e o $records são os dados que ele irá incluir. (olhem o CookBook, tem mais coisa [6]).

Agora é só fazermos os testes. Para fazermos nossos testes, vamos usar a convenção de nome de função do CakePHP. Iniciamos todas as funções que queremos que sejam executadas no Case com o seguinte formato testXXXXXX, cada função será um teste. Dentro desta função você usa os Asserts. No exemplo, vou testar uma funcionalidade do meu model que retorna o número de Topicos publicados.

1
2
3
4
5
6
function testNumeroPublicados(){
	$modelo =& new Topico();
	$esperado = 1;
	$encontrado = $modelo->numeroPublicado();
	$this->assertEqual($esperado,$encontrado);
}

Simples não? A lógica do método numeroPublicado() não importa, ele pode até mesmo não exitir, o que estamos fazendo aqui é o teste. Uma coisa importante de se lembrar é que temos liberdade de “estragar” o banco, pois os fixtures vão recompo-lo novamente no próximo teste, exemplo:

1
2
3
4
5
6
7
8
9
10
function testNumeroPublicados(){
	$modelo =& new Topico();
	$esperado = 1;
	$encontrado = $modelo->numeroPublicado();
	$this->assertEqual($esperado,$encontrado);
	$modelo->publicarId(2);
	$esperado = 2;
	$encontrado = $modelo->numeroPublicado();
	$this->assertEqual($esperado,$encontrado);
}

Entenderam? Agora é só melhorando os testes, forçando algumas situações, algo que possa dar problemas. Bem, escrever teste é como escrever código, vocês vão ter que melhorar, refatorar, pensar em novas lógicas, etc. 

Bem pessoal, espero ter ajudado. Com mais calma eu vou melhorar o que escrevi aqui. Mas agora eu quero que vocês tentem em casa, no trabalho, façam perguntas e o mais importante: testem suas aplicações completamente. 

Abraços. 

[1]http://www.improveit.com.br/xp/praticas/tdd 
[2]http://simpletest.org/ 
[3]http://simpletest.org/api/SimpleTest/UnitTester/UnitTestCase.html 
[4]http://debuggable.com/posts/testing-models-in-cakephp—now-let%27s-get-rid-of-the-unnecessary-modeltest-classes-!:4890ed55-be28-4d4a-ba4c-7fd64834cda3
[5]Comando: php cake.php -app aplicacao schema generate // isto criará um 
arquivo schema.php no na pasta /aplicacao/config/sql/ 
[6]http://book.cakephp.org/view/358/Preparing-test-data

Pedrini: Grande abraço e obrigado por ajudar a todos nós.

17 agosto 2008

Asset de JS e CSS no CakePHP

Arquivado em: CakePHP — Tags:, , , , — Juan Basso @ 11:37 pm

Pessoal,

Peguei a versão do Asset feita pelo Matt Curry no bakery no artigo Automatic JavaScript and CSS Packer, depois atualizado em seu site (CakePHP Asset Packer Helper) e fiz algumas modificações.

As modificações que fiz não são grandes coisas, mas algumas coisas úteis, como procurar arquivos de JS e CSS nas pastas de vendors e plugins, algumas otimizações e configuração de quais assets deseja e pode utilizar (por exemplo, se você configurar que quer fazer asset packer no JS e não tiver o vendor necessário, ele não fará para não estragar seu código).

Para instalar em seu site, segue o procedimento:

Baixar os seguintes arquivos:

Feito isso, usar os helpers $html e $javascript para adicionar, mas sempre usar inline como false. Além disso, no AppController, colocar o Asset na lista de helpers.

No lugar do $scripts_for_layout, colocar $asset->scripts_for_layout().

Pronto, só isso e todos seus CSS e JS serão packeds.

Abraços e qualquer coisa é só comentar.

30 julho 2008

Usando FlexiGrid com CakePHP

Arquivado em: CakePHP, Tutoriais — Tags:, , , , , — Juan Basso @ 12:05 am

Pessoal,

Depois de escrever sobre como usar o TableSorter com CakePHP, vou escrever agora sobre o FlexiGrid. Mostrar como implementar o exemplo mais sofisticado que eles apresentam no site deles.

Primeiramente, vamos baixar os arquivos necessários:

  • jQuery: http://jquery.com (mais recente no momento é a 1.2.6)
  • FlexiGrid: http://www.webplicity.net/flexigrid/ (estou me baseando na versão 1.0b3)
  • Colocar os arquivos (jquery.js e flexigrid.js) na pasta vendors\js ou webroot\js, conforme sua preferência.

    Agora na view que vai mostrar a tabela:

    Carregar os javascripts:

    1
    
    <?php $javascript->link(array('jquery', 'flexigrid'), false); ?>

    Feito isso, incluir o seguinte código na página para exibir a tabela (PS: esse código eu copiei exatamente como está na página do Flexigrid):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    
    <style>
    	.flexigrid div.fbutton .add {
    		background: url(css/images/add.png) no-repeat center left;
    	}	
     
    	.flexigrid div.fbutton .delete {
    		background: url(css/images/close.png) no-repeat center left;
    	}	
    </style>
     
    <table id="flex1" style="display:none"></table>
     
    <script type="text/javascript">
    	$("#flex1").flexigrid({
    		url: '<?php echo Router::url(array('controller' => 'flexi', 'action' => 'index'), true); ?>',
    		dataType: 'json',
    		colModel : [
    			{display: 'ISO', name : 'iso', width : 40, sortable : true, align: 'center'},
    			{display: 'Name', name : 'name', width : 180, sortable : true, align: 'left'},
    			{display: 'Printable Name', name : 'printable_name', width : 120, sortable : true, align: 'left'},
    			{display: 'ISO3', name : 'iso3', width : 130, sortable : true, align: 'left', hide: true},
    			{display: 'Number Code', name : 'numcode', width : 80, sortable : true, align: 'right'}
    		],
    		buttons : [
    			{name: 'Add', bclass: 'add', onpress : test},
    			{name: 'Delete', bclass: 'delete', onpress : test},
    			{separator: true}
    		],
    		searchitems : [
    			{display: 'ISO', name : 'iso'},
    			{display: 'Name', name : 'name', isdefault: true}
    		],
    		sortname: "iso",
    		sortorder: "asc",
    		usepager: true,
    		title: 'Paises',
    		useRp: true,
    		rp: 15,
    		showTableToggleBtn: true,
    		width: 700,
    		height: 200,
    		pagestat: 'Mostrando {from} até {to} de {total} itens',
    		procmsg: 'Processando, aguarde...',
    		nomsg: 'Nenhum item'
    	});
     
    	function test(com,grid) {
    		if (com == 'Delete') {
    			confirm('Excluir ' + $('.trSelected',grid).length + ' itens?')
    		} else if (com == 'Add') {
    			alert('Adicionar novo item');
    		}
    	}
    </script>

    Pronto, nossa view está pronta para exibir os dados. Agora vamos para a parte dos dados:

    Vamos começar pelo controller (controllers/flexi_controller.php):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    <?php
     
    class FlexiController extends AppController {
     
    	var $name = 'Flexi';
    	var $uses = array('Country');
     
    	function index() {
    		Configure::write('debug', 0);
    		extract($this->params['form']);
    		$this->paginate = array(
    			'limit' => $rp,
    			'page' => $page,
    			'order' => array(
    				$sortname => $sortorder
    			)
    		);
    		if ($query) {
    			$this->paginate['conditions'][$qtype . ' LIKE'] = '%' . $query . '%';
    		}
    		$this->header('Content-type: text/x-json');
    		$this->set('paises', $this->paginate('Country'));
    		$this->layout = 'ajax';
    	}
     
    }
     
    ?>

    Duas considerações: desativar o debug é para que ele não exiba erros/warnings de PHP e o tempo de carregamento no final. O layout ajax é para ele não incluir nada a mais que o que eu colocar na view.

    Bem, feito isso no controller, vamos para a view (views/flexi/index.ctp), montar nosso JSON na mão… :)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    <?php $params = $paginator->params(); ?>
    { page: <?php echo $params['page']; ?>, total: <?php echo $params['count']; ?>, rows: [
    <?php
    $registros = array();
    foreach ($paises as $pais) {
    	$registros[] = "{id: '" . $pais['Country']['iso'] . "', cell: ['" . $pais['Country']['iso'] . "', '" . $pais['Country']['name'] . "', '" . $pais['Country']['printable_name'] . "', '" . $pais['Country']['iso3'] . "', '" . $pais['Country']['numcode'] . "']}";
    }
    echo implode(',', $registros);
    ?> ] }

    Pronto, isso aí vai gerar o JSON necessário para o Flexigrid. Já dá para brincar com ordenação, troca de páginas, filtro…

    Qualquer coisa, só comentar!

    28 julho 2008

    Usando o TableSorter com CakePHP

    Arquivado em: CakePHP, Tutoriais — Tags:, , , , , , , — Juan Basso @ 9:26 pm

    Pessoal, depois de um tempo sumido devido a alguns trabalhos que me consumiram muito tempo, estou voltando…

    Hoje vou falar de uma experiência que tive com o TableSorter com CakePHP na construção de uma página, não me atendo muito a detalhes de design, mas da parte funcional. No grupos de CakePHP PT eu tinha falado que ia fazer, mas fazem quase dois meses e nada, porém agora lá vai… Bill: desculpe a demora. :)

    Primeiro, baixem o jQuery (http://jquery.com) e o plugin TableSorter (http://tablesorter.com).

    Extraia os arquivos baixados (jquery.js e jquery.tablesorter.js) em alguma vendors\js ou webroot\js. Eu particularmente prefiro deixar na pasta vendors, pois são plugins de terceiros ou que não são exclusivos da aplicação. Em contra partida, deixar na pasta webroot polpa o trabalho do servidor executar o cake para procurar, reduzindo o tempo de resposta. Aí vai do gosto de cada um. Eu prefiro perder tempo para deixar as coisas nos seus devidos lugares…

    No controller, você precisa apenas declarar que vai usar o helper Javascript:

    1
    
    var $helpers = array(..., 'Javascript');

    Feito isso, criamos uma tabela na view do que queremos mostar:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    <table border="0" id="detalhe_compra">
    	<caption><?php __('Detalhe por compra'); ?></caption>
    	<thead>
    		<tr>
    			<th><?php __('Pedido'); ?></th>
    			<th><?php __('Data'); ?></th>
    			<th><?php __('Cliente'); ?></th>
    			<th><?php __('Valor'); ?></th>
    		</tr>
    	</thead>
    	<tfoot>
    		<tr>
    			<td colspan="3">&nbsp;</td>
    			<td><?php echo $number->currency($totalPedidos); ?>
    		</tr>
    	</tfoot>
    	<tbody>
    <?php foreach ($pedidos as $pedido): ?>
    		<tr>
    			<td><?php echo $pedido['Pedido']['numero']; ?></td>
    			<td><?php echo $pedido['Pedido']['data']; ?></td>
    			<td><?php echo $pedido['Cliente']['nome']; ?></td>
    			<td><?php echo $pedido['Pedido']['valor']; ?></td>
    		</tr>
    <?php endforeach; ?>
    	</tbody>
    </table>

    Depois, ainda na mesma view, basta colocar o seguinte código para carregar os arquivos de javascript no head:

    1
    
    <?php $javascript->link(array('jquery', 'jquery.tablesorter'), false); ?>

    Em seguida, configurar o TableSorter para agir sobre a tabela:

    1
    2
    3
    4
    5
    6
    
    <?php
    $javascript->codeBlock('
    	$(document).ready(function(){
    		$("#detalhe_compra").tablesorter({decimal: ",", dateFormat: "uk"});
    	});', array('inline' => false));
    ?>

    Nas configurações da tabela, defini que os números possuem o vírgula como separador decimal e a data no formato inglês (similar ao nosso).

    Pronto, só isso já faz funcionar o TableSorter. Outras configurações, podem olhar no site do TableSorter e ver. Lá é bem documentado e tranquilo.

    Abraços e boa sorte a todos, qualquer coisa, é só comentar.

    30 junho 2008

    Usando NOT IN nas pesquisas e exclusões

    Arquivado em: CakePHP — Juan Basso @ 10:25 pm

    Pessoal,

    Depois de um tempo sumido, estou aí postando. Muito trabalha impede a gente de ficar postando toda hora, infelizmente.

    Essa dica de agora, aprendi fazendo uma aplicação que precisei. Precisava apagar todas as fotos de um imóvel que não estivessem em uma lista. Para fazer isso, usei o seguinte:

    1
    
    $this->Photo->deleteAll(array('NOT' => array('Photo.id' => $this->data['Photos']), 'Photo.building_id' => $id);

    Onde $this->data['Photos'] é um array com os id’s que não quero excluir.

    Simples não?

    Abraços e até a próxima.

    4 junho 2008

    Sai RC1 do CakePHP 1.2

    Arquivado em: Outros — Tags:, , , , — Juan Basso @ 10:27 pm

    Boas novas, cakers!

    Saiu hoje a nova versão do CakePHP 1.2, através da release candidate (RC) 1, usando a revisão 7119.

    As maiores alterações são alterações no modo de utilizar as condições e colocar vários métodos em desuso.

    Para quem quiser mais informações sobre o lançamento, consulte o link oficial (no Bakery). Quem quiser fazer o download agora, clique aqui.

     

    Abraços e bom uso para todos.

    2 junho 2008

    Novos métodos de callback para componentes

    Arquivado em: CakePHP — Tags:, , — Juan Basso @ 1:22 pm

    Recentemente, foram adicionados três novos métodos de callback para os componentes: beforeRender, beforeRedirect e shutdown.

    Como o próprio nome já diz, o beforeRender() é chamado antes da view ser renderizada, mas depois do beforeRender() do controller:

    1
    2
    3
    4
    
    // no seu componente
    public function beforeRender($controller) {
        // faça alguma coisa
    }

    O beforeRedirect() também é obvio, é chamado antes de um redirect ser executado:

    1
    2
    3
    4
    
    // no seu componente
    function beforeRedirect($controller, $url, $status = null, $exit = true) {
        // faça alguma coisa
    }

    Retornando um valor você pode substituir os valores que foram passados no redirect original. Por exemplo:

    1
    2
    3
    4
    
    function beforeRedirect($controller, $url, $status = null, $exit = true) {
        // return '/redirect/target';  // um simples valor é tratado como uma URL
        return array('url' => '/redirect/target', 'status' => 307);
    }

    O último método de callback é o shutdown(). Ele é chamado depois de Controller::render() e antes de Controller::afterFilter():

    1
    2
    3
    4
    
    // no seu componente
    function shutdown($controller) {
        // faça alguma coisa
    }

    Continuem seus bolos…

    Texto traduzido de New callback methods for components

    Posts mais antigos »

    Powered by WordPress