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?
Posts relacionados: