Integrar o Smarty como motor de renderização no Yaf (Yet Another Framework) é uma prática comum, mas a abordagem padrão via Bootstrap.php geralmente limita a estrutura de pastas ao diretório fixo views. Para projetos que exigem caminhos de templates customizados ou baseados em módulos, uma estratégia baseada em Plugins é mais eficiente.
Por que evitar o Bootstrap para inicializar o View Engine?
Ao definir o Smarty dentro de _initSmarty() no Bootstrap.php, o Yaf ainda não processou as rotas. Isso significa que o nome do módulo, controller ou action ainda não está disponível. Ao utilizar um Plugin no gancho (hook) routerShutdown, garantimos que o roteamento foi concluído, permitindo definir diretórios de templates específicos para cada módulo.
Implementação do Plugin de Layout
O exemplo abaixo demonstra como interceptar o fluxo após o roteamento para injetar o adaptador do Smarty e desativar a renderização automática do Yaf.
<?php
class TemplatePlugin extends Yaf_Plugin_Abstract {
public function routerShutdown(Yaf_Request_Abstract $request, Yaf_Response_Abstract $response) {
$dispatcher = Yaf_Dispatcher::getInstance();
// Desativa a renderização padrão para evitar conflitos de caminhos
$dispatcher->autoRender(false);
// Inicializa o adaptador customizado do Smarty
$smartyEngine = new SmartyAdapter();
$dispatcher->setView($smartyEngine);
}
}
Desenvolvendo o Adaptador Smarty
Para que o Yaf aceite o Smarty, é necessário implementar a interface Yaf_View_Interface. Abaixo, uma implementação que gerencia caminhos de forma dinâmica conforme o módulo atual.
<?php
class SmartyAdapter implements Yaf_View_Interface {
public $instance;
protected $_tplDir;
public function __construct() {
// Supondo que a classe Smarty já esteja carregada via autoload
$this->instance = new Smarty();
$this->instance->left_delimiter = '{{';
$this->instance->right_delimiter = '}}';
$this->instance->setCompileDir(DATA_PATH . '/templates_c');
$this->instance->setCacheDir(DATA_PATH . '/cache');
$req = Yaf_Dispatcher::getInstance()->getRequest();
$module = $req->getModuleName();
// Define o caminho do template baseado no módulo (ex: application/modules/Admin/tpl)
if (strtolower($module) == 'index') {
$path = APP_PATH . '/templates';
} else {
$path = APP_PATH . '/modules/' . ucfirst($module) . '/tpl';
}
$this->setScriptPath($path);
}
public function setScriptPath($path) {
$this->instance->setTemplateDir($path);
$this->_tplDir = $path;
}
public function getScriptPath() {
return $this->_tplDir;
}
public function assign($name, $value = NULL) {
$this->instance->assign($name, $value);
}
public function display($tpl, $vars = NULL) {
// É recomendável concatenar o caminho completo para evitar erros de localização
$this->instance->display($this->_tplDir . '/' . $tpl);
}
public function render($tpl, $vars = NULL) {
return $this->instance->fetch($this->_tplDir . '/' . $tpl);
}
}
Considerações Técnicas Importantes
1. Gerenciamento do AutoRender
O método $dispatcher->autoRender(false) é crucial. Se mantido como true, o Yaf tentará localizar um arquivo .phtml dentro da pasta views padrão após a execução da action, o que resultará em erros de arquivo não encontrado, já que estamos movendo os templates para diretórios personalizadso (como tpl ou templates).
2. Sobrescrita do setScriptPath
O Yaf possui um comportamento interno que chama setScriptPath automaticamente antes do dispatch. Por isso, a implementação dentro do adaptador deve ser resiliente. No código acima, garantimos que o Smarty aponte para o local correto através da variável $this->_tplDir.
Exemplo de Uso no Controller
Com a configuração via Plugin, o uso dentro das Actions permanece limpo e intuitivo:
<?php
class UserController extends Yaf_Controller_Abstract {
public function profileAction() {
$this->getView()->assign("username", "DevSenior");
// O arquivo será buscado em: application/modules/User/tpl/profile.tpl
$this->getView()->display("profile.tpl");
}
}
Esta abordagem oferece total controle sobre a estrutura de diretórios do projeto, permitindo que a camada de visão seja organizada de formma modular sem as restrições impostas pelas convenções padrão do framwork.