Logando queries no Shell do CakePHP
Se você é como eu, adora criar shells em projetos CakePHP. São fáceis, herdam pouca estrutura e te dão acesso a quase tudo que precisa para tarefas de manutenção.
Apesar de todos os pontos positivos, passei por um problema sério recentemente: a incapacidade de se extender sua classe super. Todo shell deve herdar a classe Shell, que é declarada no core do CakePHP (cake/console/libs/shell.php). Este pequeno fato torna inviável qualquer mudança na classe Shell, já que alterar código terceiro em um projeto não é algo que eu considero inteligente.
A solução foi criar uma classe intermediária, assim como temos o AppController e o AppModel, podemos ter o AppShell.
Crie um arquivo app.php no caminho app/vendors/shells/app.php e crie sua classe AppShell:
<?php class AppShell extends Shell { }
Ok, temos uma classe intermediária que podemos extender à vontade, é só fazer com que nossos shells extendam AppShell, com um pequeno porém: o Cake não vai incluir por padrão o arquivo de sua base class. E agora?
Simples! Vamos incluir o arquivo usando o método canivete suíço App::import.
<?php App::import('Shell', 'App'); class SomeApplicationSpecificShell extends AppShell { // Call some parent methods }
E é só isso!
Mas o que você vai colocar na sua super classe? Eu tenho uma sugestão.
Sinto muita falta do element sql_dump, que apresenta um log de todas as transações ocorridas nos datasources durante o load da página. Abri o código do element e portei para nossa classe de shell:
<?php class AppShell extends Shell { public function getDatabaseLogs() { if (!class_exists('ConnectionManager') || Configure::read('debug') < 2) { return false; } $sources = ConnectionManager::sourceList(); if (!isset($logs)) { $logs = array(); foreach ($sources as $source) { $db =& ConnectionManager::getDataSource($source); if (!$db->isInterfaceSupported('getLog')) { continue; } $logs[$source] = $db->getLog(); } } $out = array(); $out[] = "Nr\tQuery\tError\tAffected\tNum. rows\tTook (ms)"; foreach ($logs as $source => $logInfo) { $text = $logInfo['count'] > 1 ? 'queries' : 'query'; $tmp = array(); foreach ($logInfo['log'] as $k => $i) { $tmp[] = ($k + 1) . "\t" . h($i['query']) . "\t{$i['error']}\t{$i['affected']}\t{$i['numRows']}\t{$i['took']}"; } $out[] = array( sprintf('(%s) %s %s took %s ms', $source, $logInfo['count'], $text, $logInfo['time']), $tmp ); } return $out; } }
Como vocês podem ver, simplesmente peguei o conteúdo do element sql_dump, removi a marcação, inseri tabulações para facilitar a visualização, joguei tudo num array e simplesmente retornei. Fica a cargo do desenvolvedor do projeto tratar e exibir a saída.
E você, que método é imprescindível em seus scripts shell?
Tags: cakephp shell, oop, shell




