[SOLUCIONADO] Agregar botones a un ef_fijo que muestra una imagen

Hola, lo que necesitaría hacer es algo similar al proyecto referencia, en el ABM de Personas.
He logrado cargar y guardar fotos para cada persona, pero me pregunto si hay forma de agregar 2 botones al ef_fijo.

  • El primero para refrescar la imagen a voluntad (es decir, reproducir lo que hace el botón del ef_captcha, o incluso lo que logro al cambiar de pestaña al ser un ci con varias pestañas… al salir y volver, se hace el set_blob y luego el get_blob, por lo que obtengo lo requerido). Sin embargo un requisito más seria que si es un alta y no se hizo un set aún del array porque faltan datos, entonces, no podría forzar el set_blob/get_blob (ya que el registro aún no existe), pero supongo que recuperando el archivo, guardandolo en forma temporal, y mostrándolo tiene que funcionar (algo similar a lo que se hace al cargar la imagen de la base de datos, pero desde el sistema de archivos).
  • El segundo para eliminar la imagen, limpiando el ef_fijo y seteando $datos[‘imagen’] en null

Desde ya, mil gracias!!

En principio me imagino asi la cosa:

  • Los botones los deberias agregar al formulario que contiene la foto y luego sacarlos a mano cuando redefinis el layout por si los queres en una posicion particular.
  • La modificacion te la va a disparar tanto el evento implicito como el boton de refrescar.

Hasta ahi lo facil, pasemos a la parte fea:

  • La imagen debe estar en un lugar que sea navegable.
  • Para el alta podrias en principio mover el archivo a un lugar seguro y luego con una variable de clase donde tengas los datos(s__nombre_var) ir copiandolo con un nombre random en el directorio navegable y asignandolo al ef_fijo.
  • Al momento de sincronizar vas a tener que agregar los datos del archivo que mantenias en la variable del punto anterior.
  • Para la eliminacion tendrias que eliminar el archivo navegable, limpiar la variable de clase y finalmente limpiar el valor del ef_upload.

No se si mas o menos era como lo venias pensando, contame un poco mas y vemos como lo vamos moldeando.
Saludos
Richard

Es ahi donde me complico… patético… en lo fácil.
Como agrego los botones (y si, tengo redefinido el layout, por código, ni siquiera con un template visual)? cual es el componente toba para definir un botón al que poder agregarle eventos?

Empece a responderte esto unas 3 veces mas o menos y siempre por algun motivo me quedo colgado.

Con el tema de los botones, los agregas normalmente como eventos del formulario, tendrias el evento de modificacion predefinido + un evento para refrescar (que maneja datos) + un evento para la eliminacion de la foto en cuestion.

Con el tema de el layout en realidad te lo planteaba por el tema de los estilos, para ellos deberias redefinir el metodo generar_botones en una subclase del formulario, de esa forma podrias controlar mejor la visualizacion de ambos botones.

Saludos

No estoy sobre el proyecto en este momento, pero sigo sin figurarme (en mi escaso conocimiento) como se agrega un botón normalmente en un formulario (es visual, o por código?).
Tendrás algún ejemplo? quizá el enlace al código del ef_captcha?
Sino, despreocupate, quedará para un versión MUY futura del sistema (no puedo ayudar en nada en estas cosas, realmente neofito!)

Lo definis en el editor en la pestaña de eventos.

Perdón!!! con preguntas así, seguro que bajo mis posibilidades de acceder a respuestas!!! PERDON DE NUEVO…
(igual, te cuento que me costó encontrarle la vuelta… MUY patético… es cuestión de conocer un poco más la herramienta)

Igual, te voy a pedir asistencia con la parte “difícil”.
(Copio todo el código por si a alguno puede servirle, aunque seguro requiere alguna corrección).

En el siguiente código recupero en $temp_archivo la foto que está en la Base de datos para guardarla.
Hasta ahí, impecable, salvo que debería según tu recomendación convertir $temp_archivo en una variable de sesión, $s__temp_archivo.


        protected $s__temp_archivo
        ...
        ...
 
	function conf__formulario_docente(toba_ei_formulario $form)
	{
		$cant_datos = $this->get_relacion()->tabla('docentes')->get_cantidad_filas();
		if ($cant_datos > 0) {
			$datos = $this->get_relacion()->tabla('docentes')->get();
			$imagen = $this->get_relacion()->tabla('docentes')->get_blob('foto');
			if (isset($imagen)) {
			  	$s__temp_nombre = md5(uniqid(time()));
			  	$s__temp_archivo = toba::proyecto()->get_www_temp($temp_nombre);
			  	$temp_imagen = fopen($s__temp_archivo['path'], 'w');
			  	stream_copy_to_stream($imagen, $temp_imagen);
			  	fclose($temp_imagen);
		  		$tamaño = round(filesize($s__temp_archivo['path']) / 1024);
			  	$datos['foto_vista_preliminar'] = "<img src='{$s__temp_archivo['url']}' alt=''>";
		  		$datos['foto'] = 'Tamaño foto actual: '.$tamaño.' kb';
			}
			$form->set_datos($datos);
		} else {
                                $cfg                              = dt_cfg_valores_por_defecto::get_configuracion();
                                $datos['id_documento_tipo']       = $cfg['id_documento_tipo_dni'];
                                $datos['id_nacimiento_localidad'] = $cfg['id_localidad_bahia_blanca'];
                                $datos['id_nacionalidad']         = $cfg['id_nacionalidad_argentina'];
                   		$datos['foto'] 			= null;
                                $form->set_datos_defecto($datos);
		}
	}

Para guardarla en la base de datos, hago lo siguiente:


	function evt__formulario_docente__modificacion($datos)
	{
		$this->get_relacion()->tabla('docentes')->set($datos);
		if (is_array($datos['foto'])) {
			$s__temp_archivo = $datos['foto']['tmp_name']; 
			$imagen = fopen($s__temp_archivo, 'rb');
			$this->get_relacion()->tabla('docentes')->set_blob('foto', $imagen);
		}		
	}

El código para refrescar, finalmente quedó de esta forma:


	function evt__formulario_docente__imagen_refrescar($datos)
	{
		$this->get_relacion()->tabla('docentes')->set($datos);
		if (is_array($datos['foto'])) {
			//Se subio una imagen
			$s__temp_archivo = $datos['foto']['tmp_name']; 
			$imagen = fopen($s__temp_archivo, 'rb');
			$this->get_relacion()->tabla('docentes')->set_blob('foto', $imagen);
		}		
	}

Pero, al intentar eliminar el archivo, y vaciar el ef_fijo que la previsualiza, no logro lo deseado, y tampoco logro que se elimine de la base de datos.


	function evt__formulario_docente__imagen_eliminar($datos)
	{
		unlink($s__temp_archivo);
		unsset($s__temp_archivo);
		$datos['foto'] = null;
		$datos['foto_vista_preliminar'] = null;
		$this->get_relacion()->tabla('docentes')->set($datos);
	}

Te agradecería (apelando a tu máxima paciencia), una ayuda en este último item…
MIL GRACIAS, y de nuevo, mil perdones

Hola, me no puedo lograr la eliminación de la imagen seleccionada. He intentado hacer lo que me decías

El segundo para eliminar la imagen, limpiando el ef_fijo y seteando $datos['imagen'] en null

pero algo me está fallando… quizá algún método tipo ef_fijo.vaciar?
El código que estoy utilizando es el siguiente:


<?php
...
	function evt__formulario_docente__imagen_eliminar($datos)
	{
		unlink($s__temp_archivo);
		unsset($s__temp_archivo);
		//resetear el ef_upload de nombre foto
		$datos['foto'] = null;
		//resetear el ef_fijo de nombre foto_vista_preliminar (es el ef que muestra la foto).
		$datos['foto_vista_preliminar'] = null;
		//$this->get_relacion()->tabla('docentes')->set($datos); //si utilizo esto me genera un error
		//$this->get_relacion()->tabla('docentes')->set_blob('foto', null); //si utilizo esto me genera un error
	}

Agradecería una última ayuda en este contexto… solo me quedaría (ya que creo que con esto elimino el archivo temporal, y la variable de sesion, pero no puedo blanquear ni el ef_upload, ni el ef_fijo.
MIL GRACIAS!!!

Por ahi lo deje muy en el aire, cuando decia de poner $datos[‘imagen’] en null me referia a quitar el valor del datos_tabla, tengo que practicar un poco mas mis explicaciones sino me voy a morir de hambre como maestro… como si hiciera alguna diferencia XD.

Venis bastante bien:


	function evt__formulario_docente__imagen_eliminar($datos)
	{
		unlink($s__temp_archivo); 
		unset($s__temp_archivo);                 

Hasta aca barbaro, borraste los temporales… pero en el conf cuando recuperes los datos, el archivo se volvera a generar, lo que necesitas seria sacarlo del datos_tabla


		//resetear el ef_upload de nombre foto
		$datos['foto'] = null;
		//resetear el ef_fijo de nombre foto_vista_preliminar (es el ef que muestra la foto).
		$datos['foto_vista_preliminar'] = null;                
		//$this->get_relacion()->tabla('docentes')->set($datos); //si utilizo esto me genera un error

Este no es el caso, pero para futura referencia en lugar de usar este metodo cuando necesites borrar el valor de unas pocas columnas puntuales te convendria hacer una llamada a ‘set_fila_columna_valor’ o ‘set_columna_valor’ dependiendo de si tenes muchas filas cargadas en el datos_tabla o solamente una.


		$this->get_relacion()->tabla('docentes')->set_blob('foto', null); //si utilizo esto me genera un error
	}

Esta es la forma en que debes borrar la foto del datos_tabla, una vez quitado del datos_tabla en el metodo conf__formulario_docente no volvera a generarte el archivo temporal y pasarte la foto, decime si por casualidad el error que te devuelve es:
“Las columnas binarias o BLOB esperan un ‘resource’, producto generalmente de un ‘fopen’ del archivo a subir a la base”

Saludos
Richard

Por ahi lo deje muy en el aire, cuando decia de poner $datos['imagen'] en null me referia a quitar el valor del datos_tabla, tengo que practicar un poco mas mis explicaciones sino me voy a morir de hambre como maestro.... como si hiciera alguna diferencia XD.
El problema es el nivel del alumnado!!!

No pude pescar el error que me tira, simplemente sale del formulario.
Creo entender lo siguiente: al presionar el botón de Eliminar en la foto (te adjunto una foto del formulario), llama nuevamente al evento de configuración del mismo? no tendría que simular el evento de modificación?
Como sea, el evento de configuracion tiene el siguiente código, para poder levantar la foto preexistente en la tabla si existiera. ¿Tendría que tener otra variable de sesión que me permita controlar si es un alta o una edición? y más aún, si es un alta, pero cargué una foto y luego la eliminé?


<?php
...
	function conf__formulario_docente(toba_ei_formulario $form)
	{
		$cant_datos = $this->get_relacion()->tabla('docentes')->get_cantidad_filas();
		if ($cant_datos > 0) {
			$datos = $this->get_relacion()->tabla('docentes')->get();
			$imagen = $this->get_relacion()->tabla('docentes')->get_blob('foto');
			if (isset($imagen)) {
			  	$temp_nombre = md5(uniqid(time()));
			  	$s__temp_archivo = toba::proyecto()->get_www_temp($temp_nombre);
			  	$temp_imagen = fopen($s__temp_archivo['path'], 'w');
			  	stream_copy_to_stream($imagen, $temp_imagen);
			  	fclose($temp_imagen);
		  		$tamaño = round(filesize($s__temp_archivo['path']) / 1024);
			  	$datos['foto_vista_preliminar'] = "<img src='{$s__temp_archivo['url']}' alt=''>";
		  		$datos['foto'] = 'Tamaño foto actual: '.$tamaño.' kb';
			}
			$form->set_datos($datos);
		} else {
            $cfg               = dt_cfg_valores_por_defecto::get_configuracion();
            $datos['foto']   = null;
            $form->set_datos_defecto($datos);
		}
	}

	function evt__formulario_docente__modificacion($datos)
	{
		$this->get_relacion()->tabla('docentes')->set($datos);
		if (is_array($datos['foto'])) {
			$s__temp_archivo = $datos['foto']['tmp_name']; 
			$imagen = fopen($s__temp_archivo, 'rb');
			$this->get_relacion()->tabla('docentes')->set_blob('foto', $imagen);
		}		
	}

Funciona todo bien… el evento refrescar, luego de cambiar el archivo, etc. Excepto la eliminación del mismo. Incluso no pude encontrar un ejemplo… el de Referencia tampoco permite eliminar la foto!!! jeje.

El error al que vos hacías referencia aparece si tildo que quiero cambiar la foto, y entonces no tomo ningún nuevo archivo en el ef_upload. Supongo que con alguna API podré chequear si el valor es nulo, y entonces, cancelar el alta y pedirle que elimine la actual (si anduviera!! jeje), o bien, que seleccione una nueva foto. Te cuento que este error aparece en el mismo caso en el proyecto de Referencia.


Te cuento mas o menos como viene el procesamiento del pedido de pagina en Toba, primeramente cuando vos presionas el boton de eliminar en JS se dispara el proceso de submit (que puede incluir o no validaciones de datos etc)… eso llega a PHP,lo que se hace ahi es procesar el evento que vos disparaste, ahi se lanza el evento ‘evt__formulario_docente__imagen_eliminar’, luego se determina cual es la pantalla a graficar y se procede a configurar las dependencias, aca vuelve a pasar por el ‘conf__formulario_docente’ (que se encuentra en dicha pantalla).

Lo que te decia yo es que si no lograbas eliminar el blob del datos_tabla (debido al error que te tira) entonces cuando pasaras por la configuracion del formulario todo se iba a reprocesar nuevamente.
Para observar cual es el error que salta (aunque se te pase de pantalla) lo que podes hacer es ir y mirar en el logger, seria la lupita dentro de toba_editor en el frame superior de la izquierda, navega hacia atras si es necesario hasta que encuentres algo que dice ‘traza’… ahi podes rastrear bien el error… con nro de linea y todo.

Como sea, el evento de configuracion tiene el siguiente código, para poder levantar la foto preexistente en la tabla si existiera. ¿Tendría que tener otra variable de sesión que me permita controlar si es un alta o una edición? y más aún, si es un alta, pero cargué una foto y luego la eliminé?

Eso no es necesario, la cosa pasa por poder eliminar la foto cuando se dispara el evento, si logras hacer eso no tendrias drama, sin embargo algo que si modificaria:


<?php
...
	function conf__formulario_docente(toba_ei_formulario $form)
	{
		$cant_datos = $this->get_relacion()->tabla('docentes')->get_cantidad_filas();
		if ($cant_datos > 0) {
			$datos = $this->get_relacion()->tabla('docentes')->get();
			$imagen = $this->get_relacion()->tabla('docentes')->get_blob('foto');
			if (isset($imagen)) {
			       $temp_nombre = md5(uniqid(time()));
			       $s__temp_archivo = toba::proyecto()->get_www_temp($temp_nombre);
			       $temp_imagen = fopen($s__temp_archivo['path'], 'w');
			       stream_copy_to_stream($imagen, $temp_imagen);
			       fclose($temp_imagen);
                               $tamano = round(filesize($s__temp_archivo['path']) / 1024);
			       $datos['foto_vista_preliminar'] = "<img src='{$s__temp_archivo['url']}' alt=''>";
                               $datos['foto'] = 'Tamaño foto actual: '.$tamano.' kb';
			}else {
                               $datos['foto']   = null;           //Agrego esto para cuando no existe imagen pero si registro
                        }
			$form->set_datos($datos);
		} else {
                            $cfg = dt_cfg_valores_por_defecto::get_configuracion();
                            $datos['foto'] = null;
                            $form->set_datos_defecto($datos);
		}
	}

Funciona todo bien... el evento refrescar, luego de cambiar el archivo, etc. Excepto la eliminación del mismo. Incluso no pude encontrar un ejemplo... el de Referencia tampoco permite eliminar la foto!!! jeje.
Jejejejej... esta hecho a proposito para que pases de un padawan toba .. a un maestro Toba :P XD.... despues lo reviso a ver que le falta.
El error al que vos hacías referencia aparece si tildo que quiero cambiar la foto, y entonces no tomo ningún nuevo archivo en el ef_upload. Supongo que con alguna API podré chequear si el valor es nulo, y entonces, cancelar el alta y pedirle que elimine la actual (si anduviera!! jeje), o bien, que seleccione una nueva foto. Te cuento que este error aparece en el mismo caso en el proyecto de Referencia.
En realidad lo que me preocupaba era que tu llamada a '$this->get_relacion()->tabla('docentes')->set_blob('foto', null);' te diera el error, pero bueno el tema es verificar que esta pasando por esa linea de codigo... fijate si podes sacar algun var_dump o un ei_arbol de algun dato para verificar que entra en el metodo.

Saludos
Richard

Hola, retomo el tema.

  1. LOGRE QUE FUNCIONE… el error que tiraba era que tenía unset escrito unsset… :stuck_out_tongue:
    El código del eliminar quedó de esta forma:
<?php...
	function evt__formulario_docente__imagen_eliminar($datos)
	{
		unlink($s__temp_archivo);
		unset($s__temp_archivo);
		$this->get_relacion()->tabla('docentes')->set_blob('foto', null);
	}

  1. Te cuento que el error al que hacías referencia, sobre el Blob esperando un recurso… lo esquivo facilmente.
    Aparecía solamente en estos casos, ingresabas al registro para modificarlo, con una foto ya en la tabla, tildabas Cambiar archivo, y antes de seleccionar realmente un archivo nuevo para cargar, con el ef_upload en blanco, presionabas el botón Refrescar.
    Solución: ver evt__formulario_docente__imagen_refrescar más abajo. Solo chequeo si el campo nombre del ef_upload tiene datos cargados.
    Pregunta: en lugar de empty($datos[‘foto’][‘name’]), hay alguna API de Toba que me permita hacerlo en forma más elegante?
<?php...
	function evt__formulario_docente__imagen_refrescar($datos)
	{
		if (!empty($datos['foto']['name'])) {
			$this->get_relacion()->tabla('docentes')->set($datos);
			if (is_array($datos['foto'])) {
				//Se subio una imagen
				$s__temp_archivo = $datos['foto']['tmp_name']; 
				$imagen = fopen($s__temp_archivo, 'rb');
				$this->get_relacion()->tabla('docentes')->set_blob('foto', $imagen);
			}
	    }		
	}

  1. Por otro lado, en las carpetas temp del proyecto y www\temp quedan generados incontables archivos temporales relacionados con esta operación.
    Como puedo solucionar esto? el fopen debe dejar los archivos abiertos…
    Habrá que cerrar los archivos una vez cargados en la tabla?
    En el evento refrescar de más arriba, algo como:
<?php....
				$imagen = fopen($s__temp_archivo, 'rb');
				$this->get_relacion()->tabla('docentes')->set_blob('foto', $imagen);
                                fclose($imagen); //esto se agregaría para eliminar archivos abiertos?
			}
	    }		
	}

Y luego, en el evento de modificacion, algo como:

<?php...
	function evt__formulario_docente__modificacion($datos)
	{
		$this->get_relacion()->tabla('docentes')->set($datos);
		if (is_array($datos['foto'])) {
			$s__temp_archivo = $datos['foto']['tmp_name']; 
			$imagen = fopen($s__temp_archivo, 'rb');
			$this->get_relacion()->tabla('docentes')->set_blob('foto', $imagen);
                        fclose($imagen); //esto se agregaría para eliminar archivos abiertos?
                        unlink($s__temp_archivo); //esto para eliminar el temporal?
                        unset($s__temp_archivo); //?
		}		
	}

MIL GRACIAS!!