Hola,
ha pasado tiempo, pero por si acaso alguien llega aquí preocupado por lo mismo que yo.
Resumo:
No me gustaba la forma en la que yiibooster se inicializaba, y había visto otras formas (versiones de Yii-strap por ejemplo). Las guias dicen que lo pongas en la configuración, pero eso hace que se inicialice en cada petición.
He hecho que en vez de inicializarse ahí, se inicialice antes renderizar una vista que lo necesite.
Todos mis controladores heredan de Controller (un Controlador generico que hereda de CController
class Controller extends CController
{
Cuando vamos a pintar una vista parcial no nos hace falta inicializar booster, ni enviar jquery al cliente, porque ya lo tiene cargado (suponiendo que lo usemos en todas las páginas, que será lo mas normal).
Asi que solo queremos que se inicialice booster y se envíe el script de jquery cuando llamemos a render (cuando vayamos a enviar al cliente una vista entera).
Esa idea me llevó a meter la inicialización yiibooster en el layout, pero es un error!
Me di cuenta de que renderPartial no llama a beforeRender (lo pone la docu),
Asi que puse esto en el beforeRender:
private $renderCalled = false;
protected $useBooster = true;
protected function beforeRender($view){
// vamos a renderizar una vista completa, inicializo booster?
if($this->useBooster){
self::initBooster();
}
// hay que enviar jquery
$this->renderCalled = true;
return parent::beforeRender($view);
}
la función initBooster es lo de siempre, pero con un flag para no llamar mas de una vez:
private static $_boosterInitialized = false;
public static function initBooster(){
if(self::$_boosterInitialized){return;};
self::$_boosterInitialized = true;
Yii::app()->getComponent("booster");
}
y aquí el renderPartial overriden
Que comprueba si hay que inicializar yiibooster y si hay o no que enviar jquery
Cuando pintemos una vista completa, yii llamará a esta funcion después de llamar a beforeRender, y todos estos flags valdrán true, pero al pintar una partialView directamente o responder json no se hará nada de esto.
public function renderPartial($view, $data=NULL, $return=false, $processOutput=false){
if($this->useBooster){
self::initBooster();
}
// No volver a cargar jquery en los partialviews
if(!$this->renderCalled){
Yii::app()->clientScript->scriptMap['jquery.js'] = false; // dont render jquery
Yii::app()->clientScript->scriptMap['jquery.min.js'] = false;
}
// Deshabilitar el logeo al final del HTML
// mejor no pintarlo en un partialview y menos aun si respondes json
if(!$this->renderCalled){
//self::disableCWebLogRoute();
}
// RENDER:
$return = parent::renderPartial($view, $data, $return, $processOutput);
return $return;
}
Esta función disableCWebLogRoute la he visto en muchos sitios,
/**
* Disables logging for sending this view
*/
public static function disableCWebLogRoute() {
$logRouter = Yii::app()->getComponent("log");
if (isset($logRouter)) {
$routes = $logRouter->getRoutes();
foreach ($routes as $route) {
if ($route instanceof CWebLogRoute) {
$route->enabled = false;
}
}
}
}
y estas funciones, dos útiles para acordarme de como se utiliza el Controller este que he montado:
/**
* Llama aqui si vas a responder desde una acción llamada por ajax para desactivar booster y el weblog
*/
public function ajaxResponse(){
$this->useBooster = false;
self::disableCWebLogRoute();
}
public function renderJSON($data){
$this->ajaxResponse();
header('Content-type: application/json');
echo CJSON::encode($data);
yii::app()->end();
}
De esta manera,
-
si vas a pintar una vista completa con yiibooster jquery y todo, el código es el mismo de siempre. Llamarás a render, y beforeRender habilitará todo para que esté listo yiibooster cuando renderice las vistas.
-
si vas a pintar una vista completa, pero estás seguro de que nunca vas a utilizar yiibooster en esta vista siempre puedes establecer $this->useBooster = false; (no lo he hecho nunca, pero funciona)
-
si vas a pintar una vista parcial, por ejemplo dentro de un tab cargado por ajax:
a ) la vista necesita yiibooster (tiene algún widget)? pues llama a renderPartial como siempre. Eso hará que se envíen los scripts necesarios, pero no jquery, para que no se pise con el jquery que ya tienes cargado en la página.
b ) no necesitas yiibooster? pues puedes llamar en el controlador a $this->ajaxResponse() y se desactiva yiibooster jquery y el weblog
-
si vas a mandar json a una peticion ajax: llama desde el controlador a $this->renderJSON($data), siendo $data el objeto php que quieras mandar tal cual a javascript. Eso se saltará la inicialización de yiiboster (que aún así no la haría, porque no llamas a ningún render), enviará la cabecera json y todo.
Siento los tochos, solo espero que a alguien le sirva algún día, a mi me ha costado que esto se comporte exactamente como yo quería pero lo he conseguido. La aplicación está en producción con yiibooster y cero problemas…
yii es la ****!

Un saludo y gracias