CrugeFancybox

De Yii Framework en Español
Saltar a: navegación, buscar

Por:

Edición de Perfil de usuario de Cruge usando Fancybox

A continuación un ejemplo para que conozcas como sacar provecho del API de Cruge en conjunto con Fancybox para realizar una ventana flotante (fancybox) que muestra los campos personalizados del usuario y permite su edición via ajax.


Al terminar el tutorial obtendrás lo siguiente: (una ventana con los campos personalizados de Cruge que se editan y validan via Ajax usando Fancybox) CrugeFancybox--Paso5.png


Prerequisitos

1) Tener instalado Cruge para gestionar los usuarios.

2) Instala Jamboree. http://christiansalazar.github.com/jamboree/

3) Instala la extensión Fancybox. http://www.yiiframework.com/extension/fancybox deberias tener esto una vez instalada:

 
christian@coco:/www/demo3/protected/extensions/fancybox$ tree
.
├── assets
│   ├── blank.gif
│   ├── fancybox.png
│   ├── fancybox-x.png
│   ├── fancybox-y.png
│   ├── fancy_close.png
│   ├── fancy_loading.png
│   ├── fancy_nav_left.png
│   ├── fancy_nav_right.png
│   ├── fancy_shadow_e.png
│   ├── fancy_shadow_ne.png
│   ├── fancy_shadow_n.png
│   ├── fancy_shadow_nw.png
│   ├── fancy_shadow_se.png
│   ├── fancy_shadow_s.png
│   ├── fancy_shadow_sw.png
│   ├── fancy_shadow_w.png
│   ├── fancy_title_left.png
│   ├── fancy_title_main.png
│   ├── fancy_title_over.png
│   ├── fancy_title_right.png
│   ├── jquery.easing-1.3.pack.js
│   ├── jquery.fancybox-1.3.4.css
│   ├── jquery.fancybox-1.3.4.js
│   ├── jquery.fancybox-1.3.4.pack.js
│   ├── jquery.mousewheel-3.0.4.pack.js
│   └── _notes
│       └── dwsync.xml
├── EFancyBox.php
└── _notes
    └── dwsync.xml

3 directories, 28 files

Paso 1

Probaremos que todo anda en su estado mas basico, para ello elegiremos una vista (views/site/index.php) y alojaremos allí un enlace a "editar tu perfil" el cual solo mostrara una ventanita fancybox, demostrando que todo esta bien instalado.

editar:

 /tuapp/protected/views/site/index.php

y colocar lo siguiente:

 
<?php 
	Yii::app()->clientscript->registerCoreScript('jquery');
	include_once('protected/extensions/fancybox/EFancyBox.php');
	$efb = new EFancyBox();
	$efb->publishAssets();
?>
<span id='profile' style='color: darkred; cursor: pointer;'>Profile</span>
<script>
	var selector = $('#profile');
	selector.click(function(){
		$.fancybox("hola");
	});
</script>

¿ Qué hemos hecho hasta aquí ?

Primero, el script PHP asegura que tanto jquery como fancybox estan disponibles, jquery por medio de CClientScript y fancybox por insercion directa via include_once, llamando a publishAssets. Si tu versión de fancybox no admite ese método entonces crealo o hazlo visible, porque quiza por defecto sea un metodo protected o private (publishAssets).

Segundo, creamos un SPAN con un texto "Profile", de color rojo oscuro con cursor de puntero, al darle click sale un mensajito "hola" en forma de fancybox.

Fancybox-cruge--Paso1.png


Paso 2

Primero crea una vista en: /tuapp/protected/views/site/profile.php con el contenido:

 <?php
 echo "LA VISTA HA SIDO RENDERIZADA";

Segundo, crea un action en /tuapp/protected/controllers/siteController.php

 
	public function actionProfile(){
		if(Yii::app()->user->isGuest)
			throw new Exception('please login first');
		$this->renderPartial('profile'); // <<--- IMPORTANTE..renderPartial, debido a que corre bajo ajax
	}


Tercero, invocas el action via ajax desde views/site/index.php.

 
<?php 
	Yii::app()->clientscript->registerCoreScript('jquery');
	include_once('protected/extensions/fancybox/EFancyBox.php');
	$efb = new EFancyBox();
	$efb->publishAssets();
?>
<span id='profile' style='color: darkred; cursor: pointer;'>Profile</span>
<script>
	var selector = $('#profile');
	selector.click(function(){
		var opts = {
			 url: 'index.php?r=/site/profile'
			,cache: false
			,async: true
			,success: function(html){
				$.fancybox(html);
			}
			,error: function(e){
				$.fancybox(e.responseText);
			}
		};
		$.ajax(opts);
	});
</script>

Finalmente, al hacer click en "Profile" debe salir el mensaje mostrado en la imagen abajo. Si no has iniciado sesión con ningun usuario saldra un fancybox con el error de "please login first" debido a la excepcion emitida en el actionProfile de siteController. **cuida que el renderPartial del action sea asi y no solo "render"**

CrugeFancybox--Paso2.png

Esta imagen muestra el contenido de la vista view/site/profile.php, obtenido mediante ajax request.


Paso 3

Probaremos que Jamboree funciona bien. Los detalles de instalacion de Jamboree estan en su website, lee los requsitos de esta wiki mas arriba para saber como. http://christiansalazar.github.com/jamboree/

Clona o descarga jamboree dentro de /tuapp/protected/extensions/jamboree/ y luego registralo en tu config/main, en imports:

 'application.extensions.jamboree.*',

Luego, edita /tuapp/protected/views/site/profile.php y agrega el siguiente codigo:

 
<?php
$main = new JamVertPanel();
$body = new JamVertPanel();

$main->add(new JamElement("H2","Editando tu Perfil"));
$main->add($body);

$main->setId('profile-form');
$main->setWidth('400px');
$body->add("Aqui ira el cuerpo del form");
$button = $main->add(new JamElement('button','Guardar Cambios'));
$button->setId('update-profile');

$main->render();
?>
<script>
	$('#update-profile').click(function(){
		alert('PRUEBA');		
	});
</script>

Al darle click al enlace "Profile" ahora saldrá lo siguiente: (al darle clic al boton sale la cajita de mensaje: OK)

CrugeFancybox--Paso3.png


Paso 4

Insertaremos los campos personalizados de Cruge en el formulario de profile.

Prerequsito: Inicia sesión como administrador de Cruge y crea algunos campos personalizados para tu sistema.


Primero necesitas crear un nuevo modelo que he llamado "CrugeProfile", guarda el siguiente código en tu directorio "models".

 
<?php
/**
 * CrugeProfile
 *	this class validates and store (save) the user defined fields for
 *	the current user.
 * 
 * @uses CFormModel
 * @package Cruge
 * @author Christian Salazar H. <christiansalazarh@gmail.com>
 * @license http://opensource.org/licenses/bsd-license.php
 */
class CrugeProfile extends CFormModel {
	private $_fields;
	public function setAttributes($values, $boolSafeOnly=true){
		// the current user
		$user = Yii::app()->user->user;
		// Load user field and values
		$this->_fields = Yii::app()->user->um->loadUserFields($user);
		// at this point the _fields array contains CrugeField with its
		// attribute _value setted to the stored and current value
		foreach($values as $k=>$v)
			if(isset($this[$k])){
				// is an attribute for this class, not cruge
				$this[$k] = $v;
			}else{
				// Cruge Area:
				// Recover values from POST to CrugeFieldValue
				foreach($this->_fields as $field)
					if($k==$field->fieldname)
						$field->setFieldValue($v);
			}
	}
	public function validate($attributes = null, $clearerrors=true){
		// validate this class attributes...not cruge..
		$validateResult = parent::validate($attributes, $clearerrors);
		// now..validate CRUGE fields:
		foreach($this->_fields as $field)
			if(!$field->validateField()){
				$this->addErrors($field->getErrors());
				$validateResult = false;
			}
		return $this->hasErrors() ? false : true;
	}
	public function save($validateFirst=true){
		if($validateFirst==true)
			if(!$this->validate())
				return false;
		// stores values from this object to Cruge.
		$user = Yii::app()->user->user;
		foreach($this->_fields as $field){
			$cfv = Yii::app()->user->um->loadICrugeFieldValue($user, $field);
			$cfv->value = $field->getFieldValue();
			if(!$cfv->save()){
				// validation error when saving...so bad.
				$this->addError($field->fieldname,
					'No se pudo guardar este valor.');
				return false;
			}
		}
		return true;	
	}
	public function rules(){
		// not required, cruge has its own rules based on cruge fields
		// this rules are defined in the cruge field setup via UI by admin.
		return array();
	}	
	public function attributeLabels(){
		return array();
	}
}


Ahora, vuelve a /tuapp/protected/views/site/profile.php y creeras el contenido del formulario, asi:

  
<?php

$main = new JamVertPanel();
$body = new JamVertPanel();

$main->add(new JamElement("H2","Editando tu Perfil"));
$main->add($body);

$main->setId('profile-form');
$main->setWidth('400px');
$button = $main->add(new JamElement('button','Guardar Cambios'));
$button->setId('update-profile');

// *****
// Lo que antes tenia $body en el paso 3 quitalo 
// y en cambio inserta lo que va desde aqui:
$um = Yii::app()->user->um;
$model = new CrugeProfile(); 
$all_defined_fields = $um->loadUserFields(Yii::app()->user->user);
$n=0;
foreach($all_defined_fields as $field){
	$n++;
	$fieldpanel = new JamVertPanel();
	$fieldpanel->setPadding('0');

	$panel = $fieldpanel->add(new JamHorzPanel());
	$panel->setBorderNone();
	$panel->setHtmlOption('margin','0');
		$req   = $panel->add($field->required ? "*" : " ");
		$label = $panel->add($um->getLabelField($field));
		$panel->add($um->getInputField($model, $field));
		$req->setColor('red');
		$req->setMarginRight('5px');
		$label->setWidth('150px');
	// this field is required to display an error after validation
	$errfield = $fieldpanel->add(new JamElement('div'));
		$errfield->setId($field->fieldname."_error");
		$errfield->addHtmlOption('class','errorinfo');
		$errfield->setColor('red');
		$errfield->setMarginLeft('10px');

	$body->add($fieldpanel);
}
if($n==0)
	$body->add("No has definido ningun campo personalizado. "
		."Ve a cruge como administrador y crea algunos");
// **** HASTA AQUI
$main->render();
?>
<script>
	$('#update-profile').click(function(){
		alert('PRUEBA');		
	});
</script>

Tu paso #4 deberia mostrar algo similar a esta imagen, recuerda previamente crear algunos campos personalizados.

CrugeFancybox---Paso4.png

Paso 5

En este paso hay que insertar codigo JS en /tuapp/protected/views/site/profile.php para que este colecte los valores de los campos de forma automatica, para finalmente pasarlos via AJAX al actionProfile el cual tambien requerirá un cambio.

Primero, preparar el actionProfile, para que reconozca el POST y le pase los atributos a CrugeProfile (modelo insertado en el paso anterior)

public function actionProfile(){
	if(Yii::app()->user->isGuest)
		throw new Exception('please login first');
// **** NUEVO CODIGO *****
	if(isset($_POST['CrugeProfile'])){
		$model = new CrugeProfile();
		$model->attributes = $_POST['CrugeProfile']; // ESTO INVOCA A CrugeProfile.setAttributes
		header("Content-type: application/json");    // lo cual pasara los valores del POST hacia
		if($model->save()){                          // los campos de cruge de forma automatica
			$r = array('ok'=>true); // ajax return value
		}else{
			$r = array('ok'=>false,'errors'=>$model->errors);
		}
		echo CJSON::encode($r); // ajax return value
		return;	
	}
// **** HASTA AQUI ****
	$this->renderPartial('profile');
}


Segundo, editar /tuapp/protected/views/site/profile.php y sustituir el codigo en la funcion "click" del boton de enviar formulario, en sustitucion poner el codigo marcado entre asteriscos:

  
<?php

$main = new JamVertPanel();
$body = new JamVertPanel();

$main->add(new JamElement("H2","Editando tu Perfil"));
$main->add($body);

$main->setId('profile-form');
$main->setWidth('400px');
$button = $main->add(new JamElement('button','Guardar Cambios'));
$button->setId('update-profile');

// Lo que antes tenia $body en el paso 3 quitalo 
// y en cambio inserta lo que va desde aqui:
$um = Yii::app()->user->um;
$model = new CrugeProfile(); 
$all_defined_fields = $um->loadUserFields(Yii::app()->user->user);
$n=0;
foreach($all_defined_fields as $field){
	$n++;
	$fieldpanel = new JamVertPanel();
	$fieldpanel->setPadding('0');

	$panel = $fieldpanel->add(new JamHorzPanel());
	$panel->setBorderNone();
	$panel->setHtmlOption('margin','0');
		$req   = $panel->add($field->required ? "*" : " ");
		$label = $panel->add($um->getLabelField($field));
		$panel->add($um->getInputField($model, $field));
		$req->setColor('red');
		$req->setMarginRight('5px');
		$label->setWidth('150px');
	// this field is required to display an error after validation
	$errfield = $fieldpanel->add(new JamElement('div'));
		$errfield->setId($field->fieldname."_error");
		$errfield->addHtmlOption('class','errorinfo');
		$errfield->setColor('red');
		$errfield->setMarginLeft('10px');

	$body->add($fieldpanel);
}
if($n==0)
	$body->add("No has definido ningun campo personalizado. "
		."Ve a cruge como administrador y crea algunos");
$main->render();
?>
<script>
	$('#update-profile').click(function(){

// ****** NUEVO CODIGO PASO 5 - DESDE AQUI *********
		// aqui se arma un argumento POST consumible por 
		// el modelo CrugeProfile basado en todos los input, select
		// y textarea que el formulario contiene dentro de si. 
		//
		var form = $('#profile-form');
		var post = { };
		form.find('input, select, textarea').each(function(){
			var name = $(this).attr('name');
			var value = $(this).val();
			post[name] = value;
		});
		// se invoca via ajax el actionProfile enviandole los valores
		// que el usuario ha introducido, validandose estos con el modelo
		// CrugeProfile
		//
		var opts = {
			url: 'index.php?r=/site/profile', data: post
			,cache: false, async: true, type: 'post', 
			success: function(resp){
				// "resp" es un objeto crear via JSON en el actionProfile
				// contiene:
				//	resp.ok (true o false) y resp.errors, el cual es un array
				// de objetos de error emitidos por CModel
				if(resp.ok==false){
					$.each(resp.errors, function(fieldname, message){
						// por cada error estamos dandole ese texto al
						// DIV creado por Jamboree mas arriba con $errField
						//
						// el wrapper <span> es requerido para evitar errores
						// en caso de que el mensaje venga con acentos o tilde
						$('#'+fieldname+'_error').html("<span>"+message+"</span>");
					});
				}
				else {
					if(resp.ok==true){
						$.fancybox("Su perfil ha sido guardado exitosamente");
						// se cierra solito..
						setTimeout($.fancybox.close, 2500);
					}else{
						alert('ocurrio un error');
					}
				}
				$.fancybox.hideActivity();
			}
			,error: function(e){
				$.fancybox(e.responseText);
				$.fancybox.hideActivity();
			}
		}
		$.ajax(opts);
// ****** NUEVO CODIGO PASO 5 - HASTA AQUI *********
	});
</script>

Listo, los campos personalizados del usuario han sido establecidos exitosamente.

CrugeFancybox--Paso5.png