Inicializar Yiibooster En El Layout

Hola a todos,

Quería postear esto aqui www.yiiframework.com/wiki/434/load-the-yii-bootstrap-extension-on-specific-actions/#add-comment pero no me deja porque soy novato.

Llevo una temporada trasteando yiistrap+yiiwheels y yiibooster, y he elegido yiibooster porque utiliza bootstrap3, y me ha parecido igual de completo.

El problema que le he visto es que da dos opciones para incializarlo:

yiibooster.clevertech.biz/getting-started.html

Según esto tengo que ponerlo en el preload cosa que no recomiendan pero que funciona o

ponerlo como filtro, y hacer que se llame inicialice en el controlador.

Pues no me gustan ninguna de las dos formas, porque la primera me complica el REST/JSON o el ajax, y la segunda me obliga a mantener la lista de las acciones muy vigilada y soy muy despistado.

Asique se me ha ocurrido llevarme la sentencia que se ejecuta en el famoso filtro:


Yii::app()->getComponent("booster"); 

En mi layout, dentro del


<head></head>

.

Y funciona…

Inyecta los scripts (js y css) misteriosamente al final del head, siempre justo a continuación del title, (digo misteriosamente porque no sé cómo hace exáctamente el procesado…)

la pregunta es: esto funciona, pero es correcto? a alguien se le ocurre alguna razón por la que no deba hacer esto?

Me gusta el hecho de que solo se inicialice cuando lo voy a usar i.e, al pintar una vista que utilice ese layout… pero no sé si me voy a encontrar con problemas mas adelante,… por ahora pinta widgets sin problemas.

Yiistrap hace una cosa parecida, se configura igual como componente en el config, los alias etc… pero segun las instrucciones de yiistrap hay que llamar desde el layout a algo asi como registerScripts. No estoy seguro de que haga alguna otra inicializacion antes, a lo mejor yiistrap no la necesita.

Aquí está el fuente que inicializa yiibooster: github.com/clevertech/YiiBooster/blob/master/src/components/Booster.php

como os digo, no veo ninguna razón para no hacer esto, pero no entiendo por qué no se les ha ocurrido a ellos y si es asi por qué no está en el manual.

Muchas gracias

Lo tengo,

así funciona mal, no había caido en que el layout se renderiza despues que la view.

Estaba funcionando porque todos los widgets que estaba probando los estaba metiendo en el layout, pero si lo metes en una vista, no está definido aun yiibooster.

Pero tengo otra opción más, y esta yo creo que es la mejor:

Tengo un controlador generico llamado Controller en components que hereda de RController (del modulo rights).

Y todos mis controladores heredan de él.

He definido la funcion beforeRender en Controller:


	

	protected $useBooster = true;

	protected function beforeRender($view){


		if($this->useBooster){

			Yii::app()->getComponent("booster"); 

		}

		

		return parent::beforeRender($view);

	}



desde el controlador podría establecer $this->useBooster cuando quisiera, incluso aqui mismo podría comprobar si


Yii::app()->request->isAjaxRequest

o si el nombre de mi action tiene la palabra ajax, o cosas así…

Esto tiene mejor pinta no?

Lo mismo, alguien que se haya peleado ya con esto, sabe si esto no se debe hacer?

un saludo y gracias

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 ****! :D :D

Un saludo y gracias