Archivo de la categoría: Yii Framework

TUTORIAL YII FRAMEWORK (CAPÍTULO 18) – CAMPOS ENMASCARADOS EN FORMULARIO

Algo muy útil en los formularios es poder enmascarar los campos, esto significa colocar los separadores automáticamente y restringir que caracteres puede ingresar el usuario a medida que se va tecleando, a continuación mostramos un ejemplo de como implementarlo en Yii, no hace falta la inclusión de una extensión.

<?php $this->widget('CMaskedTextField', array(
'model' => $model,
'attribute' => 'telefono_persona',
'mask' => '(9999)-999-9999',
'htmlOptions' => array('size' => 11)
));
?>

En ejemplo model es el modelo en cuestión, attribute es el nombre del campo, mask es el tipo de máscara que le quieres colocar y en htmlOptions indicas las características HTML que quieres que tenga tu campo. En la mascara si usamos ’9′ indicamos que solo se puede teclear números, ‘a’ es solo letras, y ‘*’ es cualquier carácter alfanumérico

TUTORIAL YII FRAMEWORK (CAPÍTULO 17) – HACER FORMULARIO PARA MULTIPLES MODELOS

Una vez realizado el CRUD de cada modelo este nos genera automáticamente un formulario con los datos del modelo, si queremos hacer un formulario que incluya los datos de dos o mas modelos debemos modificar varias lineas de código.

En el ejemplo que explico a continuación tenemos dos modelos, el modelo Personal cuyos datos son id_personal, nombre_personal y id_estado y el modelo Estado con id_estado y nombre_estado, de mas está decir que Personal es alimentado por Estado, lo primero que haremos es modificar la vista _form de Personal.

<div class="form">
<?php $form = $this->beginWidget('CActiveForm', array( 'id'=>'user-form',
'enableAjaxValidation'=>true, ));
if ($a->isNewRecord==false) { $b=Estado::model()->findByPk($a->id_estado); }
echo $form->errorSummary(array($a,$b)); ?>
<div class="row">
<?php echo $form->labelEx($a,'nombre_personal'); ?>
<?php echo $form->textField($a,'nombre_personal'); ?>
<?php echo $form->error($a,'nombre_personal'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($b,'nombre_estado'); ?>
<?php echo $form->textField($b,'nombre_estado'); ?>
<?php echo $form->error($b,'nombre_estado'); ?>
</div>
<div class="row buttons">
<?php echo CHtml::submitButton($a->isNewRecord ? 'Crear' : 'Actualizar'); ?>
</div> <?php $this->endWidget(); ?> </div></p>

Con ese código incluimos el campo nombre_estado del modelo Estado en el formulario de Personal, también agregamos en el parámetro errorSummary el modelo $b, que en este caso es Estado, con esto nos valida el formulario con las restricciones que hayamos puesto en el rules() de ambos modelos, por otra parte preguntamos si se está creando un nuevo registro o no, en caso de ser una actualización cargamos la información del modelo Estado, de Personal nos la carga automáticamente.

En el caso de las vistas create.php y update.php cambiamos la siguiente linea:

<?php echo $this->renderPartial('_form', array('model'=>$model)); ?>

por esta

<?php echo $this->renderPartial('_form', array('a'=>$a, 'b'=>$b)); ?>

Ahora modificamos la acción create:

public function actionCreate()
{
$a=new Personal;
$b=new Estado;
$this->performAjaxValidation(array($a,$b));
if(isset($_POST['Personal'],$_POST['Estado']))
{
$a->attributes=$_POST['Personal'];
$b->attributes=$_POST['Estado'];
$sql='select max(id_estado) from estado;';
$connection=Yii::app()->db;
$command=$connection->createCommand($sql);
$row=$command->queryRow();
$row["max"]++;
$b->id_estado=$row["max"];
$a->id_estado=$row["max"];
if($b->save() && $a->save())
$this->redirect(array('view','id'=>$a->id_personal));
}
$this->render('create',array('a'=>$a,'b'=>$b));
}
<p style="text-align: justify;">

Lo primero que hacemos es instanciar los modelos Personal y Estado, luego si los datos pasan la validación determinamos el mayor id de estado, se lo asignamos al dato id_estado de cada modelo y guardamos los datos.
Para update hacemos algo parecido:

public function actionUpdate($id)
{
$a=new Personal;
$b=new Estado;
$this->performAjaxValidation(array($a,$b));
$a=$this->loadModel($id);
if(isset($_POST['Personal'],$_POST['Estado']))
{
$a->attributes=$_POST['Personal'];
$b->attributes=$_POST['Estado'];

$b->id_estado=$a->id_estado;
$b->setIsNewRecord(false);
if($a->save() && $b->update())
$this->redirect(array('view','id'=>$a->id_personal));
}
$this->render('update',array('a'=>$a,'b'=>$b));
}
<p style="text-align: justify;">

De igual forma que con el create validamos los datos, guardamos y direccionamos. En definitiva hemos hecho un formulario en el que guardamos datos de dos modelos distintos, es un ejemplo sencillo pero válido, si tus modelos tienen mas datos lo incluyes en el _form y si quieres agregar más modelos al form se hace de la misma forma.

TUTORIAL YII FRAMEWORK (CAPÍTULO 16) – GUARDAR AUTOMÁTICAMENTE USUARIO Y FECHA DE CREACIÓN Y MODIFICACIÓN

Nos descargamos la librería de http://www.yiiframework.com/extension/blameable-behavior/ y la pegamos en /component/ , no olvides darle permisos. En el modelo en cuestión copiamos la siguiente función:

public function behaviors()
{
return array(
'CTimestampBehavior' => array(
'class' => 'zii.behaviors.CTimestampBehavior',
'createAttribute' => 'created_date',
'updateAttribute' => 'modified_date',
'setUpdateOnCreate' => true,
),
'BlameableBehavior' => array(
'class' => 'application.components.behaviors.BlameableBehavior',
'createdByColumn' => 'created_by',
'updatedByColumn' => 'modified_by',
),
);
}
<p style="text-align: justify;">

Donde created_date, modified_date, created_by y modified_by son los datos de nuestra tabla en donde queremos guardar los datos. Si no tenemos uno de los datos podemos comentar esa linea de código.

TUTORIAL YII FRAMEWORK (CAPÍTULO 15) – NO MOSTRAR INDEX.PHP EN LAS URL

Si deseamos que los módulos de nuestro sitio puedan ser accedidos así: /miproyecto/contact y no así:  /miproyecto/index.php&r=contact debemos hacer varios cambios en nuestro proyecto. En primer lugar ejecutamos en la consola de linux: a2enmod rewrite, abrimos /etc/apache2/SiteAvailables/default y cambiamos “Allowoverride=None” por “Allowoverride=All” (se encuentra en dos lineas distintas), luego cambiamos la dirección de nuestro archivo .htaccess de nombre_proyecto/protected/ a nombre_proyecto/, .htaccess es un archivo oculto, para mostrar los archivos ocultos usamos el atajo control + h.
Abrimos el .htaccess y pegamos los siguiente:

RewriteEngine on
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule . index.php

Finalmente vamos a /protected/config/main.php y en el arreglo component agregamos:

'urlManager'=>array(
'urlFormat'=>'path',
'showScriptName'=>false,
'caseSensitive'=>false,
),

Con esto hemos limpiado las URLs de nuestro sistema, si nuestros controladores contienen mayúsculas es necesario colocar el atributo ‘caseSensitive’ en true.

TUTORIAL YII FRAMEWORK (CAPÍTULO 14) – CAMPO CON AUTOCOMPLETAR

La idea es tener un campo de texto en el que apenas empecemos a ingresar texto se nos liste una serie de resultados que hayan coincidido con ese texto, en la vista donde va a estar el campo debemos colocar el siguiente código:

if ($model->estado0!='')
{
$value=$model->estado0->nombre_estado;
}
else {
$value='';
}
echo $form->hiddenField($model, 'estado');
$this->widget('zii.widgets.jui.CJuiAutoComplete', array(
'name'=>'estado',
'model'=>$model,
'value'=>$value,
'sourceUrl'=>$this->createUrl('ListarEstados'),
'options'=>array(
'minLength'=>'3',
'showAnim'=>'fold',
'select' => 'js:function(event, ui)
{ jQuery("#Contrato_estado").val(ui.item["id"]); }',
'search'=> 'js:function(event, ui)
{ jQuery("#Contrato_estado").val(0); }'
),
));

En el código anterior validamos que el campo no esté vacío en la base de datos, de estar vacío es que se está creando un nuevo registro o no se seleccionó ningún estado, luego creamos el campo de auto completar colocandole el nombre, el nombre del modelo, el valor por defecto, cantidad mínima para realizar la búsqueda y la función que guarda el id del campo seleccionado.

Copiamos la función ListarEstados en nuestro controlador:

public function actionListarEstados($term) {
$criteria = new CDbCriteria;
$criteria->condition = "LOWER(nombre_estado) like LOWER(:term)";</p>
$criteria->params = array(':term'=> '%'.$_GET['term'].'%');
$criteria->limit = 30;
$data = Estado::model()->findAll($criteria);
$arr = array();
foreach ($data as $item) {
$arr[] = array(
'id' => $item->id,
'value' => $item->nombre_estado,
'label' => $item->nombre_estado,
);
}
echo CJSON::encode($arr);
}

En la función de arriba definimos la condición que va a tener nuestro query, en nuestro caso buscaremos por nombre_estado indiferentemente minúsculas y mayúsculas utilizando un like ‘% %’, la máxima cantidad de resultados será de 30, los datos provienen del modelo Estado, el campo a guardar es el id y el que mostraremos es el nombre del estado.

Hay que darle permisos a los usuarios para utilizar la acción ListarEstados.

TUTORIAL YII FRAMEWORK (CAPÍTULO 13) – COMBOS DEPENDIENTES

La idea es la siguiente: Queremos dos combos, Tipo Organismo y Organismo, la idea es que al momento de escoger un tipo de organismo se despliegue en el segundo combo los distintos organismos que pertenecen a ese tipo para ello utilizamos el siguiente código en el _form:

 // Tipo de organismos
 <div class="row">
 <?php echo $form->labelEx($model,'id_tipo_org');
 // Nombre de la etiqueta a mostrar ej: Tipo Organización
 $departamento = new CDbCriteria;
 // Preparamos los parámetros de búsqueda
 $departamento->order = 'descripcion ASC';
 // ordenamos alfabéticamente
 echo $form->dropDownList($model,'id_tipo_org',
 // id_tipo_org es el nombre del campo en el modelo
 CHtml::listData(TipoOrgG::model()->findAll($departamento),
 // TipoOrgG es el modelo en el que se buscaran los datos
 'id_tipo_org','descripcion'),
 // id_tipo_org es el dato que se quiere guardar y
 // descripción lo que se quiere mostrar
 array('ajax' => array('type' => 'POST',
 'url' => CController::createUrl('Correspondencia/cargarorganismos'), //
 la acción que va a cargar el segundo div
 'update' => '#Correspondencia_id_org_g'
 // el div que se va a actualizar
 ),'prompt' => 'Seleccione un Tipo'
 // Valor por defecto
 )
 );
 echo $form->error($model,'id_tipo_org'); ?>
 </div>
 // Segundo Combo, organismos
 <div class="row">
 <?php echo $form->labelEx($model,'id_org_g');

if ($model->isNewRecord==1)
 //Si se está creando un registro nuevo
 {
 echo $form->dropDownList($model,'id_org_g',
 array('0' => 'Seleccione un Organismo'));
 // se muestra solo Seleccione un Organismo
 }
 else {
 $tipo=$model->id_tipo_org;
 // Si se está modificando un registro
 $sql="select count(id_org_g) from organismos_g where id_tipo_org='$tipo';";
 //
 $connection=Yii::app()->db;
 //
 $command=$connection->createCommand($sql);
 //
 $row=$command->queryRow();
 //
 $bandera=$row['count'];
 //
 if ($bandera==0) {
 //
 echo $form->dropDownList($model,'id_org_g',
 array('0' => 'Seleccione un Organismo')); }
 // Si el tipo de organismo no tiene ningún
 else {
 // organismo solo muestra Seleccione un Organismo
 echo $form->dropDownList($model,'id_org_g',
 CHtml::listData(OrganismosG::model()->findAllBySql(
 //Aquí van los datos de la búsqueda del segundo combo
 "select * from organismos_g where id_tipo_org
 =:keyword order by id_org_g=:clave2 asc",
 array(':keyword'=>$model->id_tipo_org,':clave2'=>$model->id_org_g)),
 'id_org_g','descripcion'));
 }
 }
 ?></div>

En el controlador colocamos la siguiente función:

 public function actionCargarorganismos()
 {
 $data=OrganismosG::model()->findAllBySql(
 "select * from organismos_g where id_tipo_org
 =:keyword or id_org_g=0 order by id_org_g=0 desc, descripcion asc",
 // Aquí buscamos los diferentes organismos que pertenecen al tipo elegido
 array(':keyword'=>$_POST['Correspondencia']['id_tipo_org']));
 $data=CHtml::listData($data,'id_org_g','descripcion');
 foreach($data as $value=>$name)
 {
 echo CHtml::tag('option', array('value'=>$value),CHtml::encode($name),true);
 }
 }

Hay que darle permisos a la acción cargarorganismos.

TUTORIAL YII FRAMEWORK (CAPÍTULO 12) – REPORTES A PARTIR DE UNA BÚSQUEDA EN EL GRID

He visto en el foro que hay muchas personas preguntando como exportar en PDF a partir de una búsqueda en la vista Admin, aquí les traigo una solución a ese problema. En el método search() del modelo en cuestión agregamos al final (antes del retorno) las siguientes lineas de código:

$_SESSION['datos_filtrados'] = new CActiveDataProvider($this, array(
'criteria'=>$criteria,
'sort'=>$sort,
'pagination'=>false,
));

Donde $criteria son los datos de filtrado y $sort el arreglo de ordenación, eso nos guardará en una variable de sesión la ultima búsqueda realizada, si no hemos realizado ninguna búsqueda estaremos guardando todos los resultados del listado, es importante colocar en false la paginación para que pueda traernos todos los resultados. En la vista admin agregar el botón de exportar con array(‘label’⇒’Exportar a PDF’, ‘url’⇒array(‘pdf’)), en la configuración del menú. En el controlador agregamos la siguiente función:

public function actionPdf()
{
$this->render('pdf');
}

Agrega la action pdf en el accessRules del controlador, para que los usuarios del sistema puedan tener permisos de utilizarla. La librería que uso y recomiendo para exportar pdf es MPDF, la pueden descargar de su pagina oficial, una vez descargada la copian en extensions. Un ejemplo para la vista pdf es el siguiente:


<? $pdf = Yii::createComponent('application.extensions.MPDF52.mpdf');
$dataProvider = $_SESSION['datos_filtrados']->getData();
$contador=count($dataProvider);
$html.='
<table align="center"><tr>
<td align="center"><b>LISTADO DE CONTRATOS</b></td>
</tr></table>
Total Resultados: '.$contador.'
<table class="detail-view2" repeat_header="1" cellpadding="1" cellspacing="1"
width="100%" border="0">
<tr class="principal">
<td class="principal" width="7%">&nbsp;N° Control</td>
<td class="principal" width="7%">&nbsp;N° Contrato</td>
<td class="principal" width="19%">&nbsp;Empresa</td>
<td class="principal" width="10%">&nbsp;Estado</td>
<td class="principal" width="9%">&nbsp;Monto Contratado</td>
<td class="principal" width="25%">&nbsp;Objeto Contrato</td>
<td class="principal" width="14%">&nbsp;Personal Actuante</td>
<td class="principal" width="9%">&nbsp;Tipo Informe</td>
</tr>';
$i=0;
$val=count($dataProvider);
while($i<$val){
$html.='
<tr class="odd">
<td class="odd" width="7%">&nbsp;'.$dataProvider[$i]
["num_control"].'</td>
<td class="odd" width="7%">&nbsp;'.$dataProvider[$i]
["num_contrato"].'</td>
<td class="odd" width="19%">&nbsp;'.$dataProvider[$i]["empresa"].'</td>
<td class="odd" width="10%">&nbsp;'.$dataProvider[$i]["estado0"]
["nombre_estado"].'</td>
<td class="odd" width="9%">&nbsp;'.$dataProvider[$i]
["monto_contratado"].'</td>
<td class="odd" width="25%">&nbsp;'.$dataProvider[$i]
["objeto_contrato"].'</td>
<td class="odd" width="14%">&nbsp;'.$dataProvider[$i]

["personal_actuante"].'</td>
<td class="odd" width="9%">&nbsp;'.$dataProvider[$i]["informe0"]
["nombre_tipo_informe"].'</td>
';
$html.='</tr>'; $i++;
}
$html.='</table>';
$mpdf=new mPDF('win-1252','LETTER-L','','',9,9,24,10,5,5);
$mpdf->WriteHTML($html);
$mpdf->Output('Reporte_Contratos.pdf','D');
exit; ?>

Como vemos al principio del ejemplo tomamos los datos filtrado mediante la variable de sesión y disponemos de ellos como queramos en el pdf.

TUTORIAL YII FRAMEWORK (CAPÍTULO 11) – EXPORTAR DEL CGRIDVIEW A PDF

Si queremos exportar registros del Cgridview a pdf a continuación te explicamos como. Lo primero que hacemos es bajarnos la ultima versión de MPDF aqui https://rapidshare.com/files/4038705402/MPDF54.zip y la colocamos en protected/extensions, copiamos en el controlador de la tabla a la que se hará el reporte la siguiente función:

public function actionPdf($id)
{
$this->render('pdf',array(
'model'=>$this->loadModel($id),
));
}

Colocamos pdf en la funcion accessRules() del mismo controlador para que los usuarios puedan acceder a la acción , en la vista admin sustituir el arreglo de los botones por el siguiente:

array(
'class'=>'CButtonColumn',
'template' => '{view} {update} {delete} {pdf}',
'buttons'=>array(
'pdf' => array(
'label'=>'Generar PDF',
'url'=>"CHtml::normalizeUrl(array('pdf', 'id'=>\$data->id
))",
'imageUrl'=>Yii::app()->request->baseUrl.'/images/pdf_icon.png',
'options' => array('class'=>'pdf'),
),
),
),

En la vista view agregamos la vista de nuestro pdf en el menu:

array('label'=>'Crear PDF', 'url'=>array('pdf','id'=>$model->id)),

en este caso la clave primaria del registro la puse como id en la base de datos, si en tu caso es “id_producto” o algo por el estilo debes cambiarlo cuando se pasa el dato a la vista.

Y por ultimo tenemos el archivo pdf.php que estará en las vistas:

<?php
$pdf = Yii::createComponent('application.extensions.MPDF52.mpdf');
$html='
<table id="yw0" class="detail-view2">
<tr class="principal">
<td colspan="2" align="center"><b>DATOS DEL CONTRATO</b></td>
<tr>
<tr class="odd">
<td> <b>N° Control</b> </td>
<td> '.$model->num_control.'</td>
</tr>
<tr class="even">
<td> <b>Trimestre Ejecucion</b> </td>
<td> '.$model->trimestre_ejecucion.'</td>
</tr>
<tr class="odd">
<td> <b>Nombre Estado</b> </td>
<td> '.$model->estado0["nombre_estado"].'</td></tr>
<tr class="even">
<td> <b>Empresa</b> </td>
<td> '.$model->empresa.'</td>
</tr>
<tr class="odd">
<td> <b>Personal Actuante</b> </td>
<td> '.$model->personal_actuante.'</td></tr>
<tr class="even">
<td> <b>Nombre Tipo Informe</b> </td>
<td> '.$model->informe0["nombre_tipo_informe"].'</td>
</tr>
<tr class="even">
<td> <b>N° Contrato</b> </td>
<td> '.$model->num_contrato.'</td>
</tr>
<tr class="odd">
<td> <b>Monto Contratado</b> </td>
<td> '.$model->monto_contratado.'</td>

</tr>
</table>';
//$header='<img src="'.Yii::app()->request->baseUrl.'/images/banner.png"/>';
$mpdf=new mPDF('win-1252','LETTER','','',15,15,25,12,5,7);
$mpdf->SetHTMLHeader($header);
$mpdf->SetFooter(' {DATE j/m/Y}|Página {PAGENO}/{nbpg}|Sistema de Contratos');
$mpdf->WriteHTML($html);
$mpdf->Output('Ficha-Contrato.pdf','D');
exit;
?>

TUTORIAL YII FRAMEWORK (CAPÍTULO 10) – BÚSQUEDAS POR FECHAS CON SYDATECOLUMN

- Bajamos la extensión de http://www.yiiframework.com/extension/sydatecolumn/ y la copiamos la clase en /protected/components/
- En nuestro CGridView colocamos la columna de la fecha así:

array(
'header'=>'Fecha Vigencia',
'name'=>'fecha_vigencia',
'value' => 'cambio_fecha($data->fecha_vigencia)' ,
'htmlOptions'=>array('width'=>'180px'),
'class'=>'SYDateColumn',
),

- Agregar en el modelo la variable donde se guardará el rango:


public $fecha_vigencia_range = array();

- Agregar a la función rules nuestro campo fecha_vigencia_range para que el formulario mantenga la fecha dada luego de la búsqueda

function rules() {
return array(
//...
array('.....,fecha_vigencia_range', 'safe', 'on'=>'search'),

- En la función search del modelo agregamos lo siguiente:

$from = $to = '';
if (count($this->fecha_vigencia_range)>=1) {
if (isset($this->fecha_vigencia_range['from'])) {
$from = $this->fecha_vigencia_range['from'];
}
if (isset($this->fecha_vigencia_range['to'])) {
$to= $this->fecha_vigencia_range['to'];
}

}
if ($from!='' || $to !='') {
if ($from!='' && $to!='') {
$from = date("d-m-Y", strtotime($from));
$to = date("d-m-Y", strtotime($to));
$criteria->compare('fecha_vigencia',">= $from",false);
$criteria->compare('fecha_vigencia',"<= $to",false);
}
else {
if ($from!='') $creation_time = $from;
if ($to != '') $creation_time = $to;
$creation_time = date("d-m-Y", strtotime($creation_time));
$criteria->compare('fecha_vigencia', "$creation_time" ,false);
}
}

TUTORIAL YII FRAMEWORK (CAPÍTULO 9) – FECHAS CON CJUIDATEPICKER

En el /protected/views/nombre_del_modelo/_form.php modifica nuestra fecha por:

<div class="row">
 <?php echo $form->labelEx($model,'fecha'); ?>
 <?php
 if ($model->fecha!='') {
 $model->fecha=date('d-m-Y',strtotime($model->fecha));
 }
 $this->widget('zii.widgets.jui.CJuiDatePicker', array(
 'model'=>$model,
 'attribute'=>'fecha',
 'value'=>$model->fecha,
 'language' => 'es',
 'htmlOptions' => array('readonly'=>"readonly"),

 'options'=>array(
 'autoSize'=>true,
 'defaultDate'=>$model->fecha,
 'dateFormat'=>'dd-mm-yy',
 'buttonImage'=>Yii::app()->baseUrl.'/images/calendar.png',
 'buttonImageOnly'=>true,
 'buttonText'=>'Fecha',
 'selectOtherMonths'=>true,
 'showAnim'=>'slide',
 'showButtonPanel'=>true,
 'showOn'=>'button',
 'showOtherMonths'=>true,
 'changeMonth' => 'true',
 'changeYear' => 'true',
 ),
 )); ?>
 <?php echo $form->error($model,'fecha'); ?>
 </div>

Antes de guardar debemos verificar que la fecha no venga vacía, eso lo hacemos en la función actionCreate, recuerda que /images/calendar.png es una imagen que hayas decido colocar allí. Al darle clic en la imagen se mostraría lo siguiente:


if($model->fecha=='') {
 $model->fecha=NULL;
 }

Si queremos formatear la fecha en la consulta a ‘d-m-Y’ debemos modificar en el /protected/views/nombre_del_modelo/view.php:

 if ($model->fecha!='') {
 $fecha=date('d-m-Y',strtotime($model->fecha));
 }
 else {
 $fecha='';
 }

Y en el ‘attributes’⇒array modificar ‘fecha’ con:

 array('name'=>'fecha', 'value'=>$fecha,),

Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.