Error de TCPDF en joomla

Joomla (todo lo que hablo es sobre la v1.5) incluye TCPDF, una librería php para generar pdfs, nunca habia usado TCPDF y fue interesante descubrir que incluye un par de funciones: writeHTMLCell() y writeHTML(), hechas para enviarles una cadena en html que represente el contenido a convertir y la función nos lo convierte a pdf, tratando de forma adecuada tablas, imagenes y demas elementos html, muy practico a diferencia de otras librerias en las que hay que estar manejando saltos de linea, imagenes, tablas, secciones, etc por separado.

TCPDF maneja muy bien el html, pero si nuestro formato depende mucho de CSS la conversión no dara una salida exactamente igual, y ni hablar de estilos creativos usando CSS 3 de hecho probe usando rotaciones, colores degradados y otras cosillas de CSS 3 en modo embebido y resulto que TCPDF da como salida unos formatos descompuestos" o incluso desordenados.

Programando un componente necesitaba generar documentos pdf y fue ahí que descubrí y recurrí a TCPDF, pero, ya habiendo implementado las llamadas a TCPDF desde mi componente, sorpresivamente, me encontre un error que de primer momento me resultó frustante e incomprensible: algo así como TCPDF error: Undefined font: xxxx Encontrar la solución fue sencillo pero implementarla de forma elegante fue lo mejor.

Viendo la definición del error es facil darse cuenta de que habia archivos que TCPDF echaba en falta, la solución es ir a nuestra instalación de joomla en la ruta: url_de_tu_instalacion_joomla/libraries/tcpdf y agregar la carpeta fonts, ésta se obtiene de la versión completa de TCPDF (descargalo desde la web de TCPDF tcpdf.org) ya que la TCPDF incluida en joomla es una versión reducida, de hecho la distribución completa de TCPDF pesa mas de 10 MB y la incluida en joomla menos de 1 MB, si descargan la versión completa de TCPDF veran que la carpeta fonts pesa mas de 10 MB por si sola así que no es muy practico agregarla toda sino abrirla y ver que fuentes necesitamos e incluirlas. De paso tambien es recomendable incluir los archivos en la carpeta root de TCPDF completo ya que la version en joomla no los incluye todos.

Hasta ahí resulta sencillo pero quizas no sea la solución optima, como en mi caso desarrollando un componente que entre sus funciones hace uso de TCPDF, no sería posible ir a cada servidor que vaya a utilizar mi componente para agregar la carpeta fonts a la carpeta TCPDF de la instalación joomla.

Y aqui viene la gran solución, lo ideal es que al hacer la instalación de nuestro componente se instale tambien las fonts en TCPDF, busque informacion sobre como al instalar un componente agregar contenido a las carpetas de librerias pero no encontre, pense usar php puro para ello pero no fue necesario, estudiando los instaladores de componentes existentes encontre la forma.

Recordemos que nuestro instalador de componente debe estar organizado en carpetas y dirigido por un archivo xml como crear instalador de componente. Supongamos que el componente con el que vamos a instalar los complementos de TCPDF se llama micomponente y la distribución tiene la siguiente estructura:



En la carpeta com_micomponente, dentro de micomponente/admin/components (el back-end) debemos agregar la carpeta libraries/tcpdf y dentro de ella lo que vamos a agregar al tcpdf de joomla, en el caso mostrado en la siguiente imagen ademas de la carpeta fonts y los archivos de la carpeta raiz de tcpdf agrege las carpetas cache, config e images originales de TCPDF:


Ahora en nuestro xml con las directivas de instalación hay un elemento que dicta los archivos y carpetas a opiar dentro de la carpeta del back-end no hay que olvidar indicar la carpeta libraries
<administration>
    <!-- ... otras directivas ... -->
    <files folder="admin/components/com_micomponente">
        <filename>controller.php</filename>
        <filename>index.html</filename>
        <filename>install.php</filename>
        <filename>micomponente.php</filename>
        <filename>uninstall.php</filename>
        <filename>install.sql</filename>
        <filename>uninstall.sql</filename>
        <folder>controllers</folder>
        <folder>elements</folder>
        <folder>media</folder>
        <folder>helpers</folder>
        <folder>models</folder>
        <folder>tables</folder>
        <folder>views</folder>
        <folder>libraries</folder>
    </files>
</administration>

Noten que dentro de los archivos indicados en la lista hay uno llamado install.php, este archivo es opcional y solo se indica cuando en el proceso de nuestra instalación se van a ejecutar operaciones php, en este caso es así, para que funcione en nuestro archivo xml debe haber una directiva como la indicada:
<installfile> install.php </installfile> 

Este archivo puede incluir varias operaciones php necesarias para la instalacion de nuestro componente, pero en el caso de lo que estamos ilustrando se trata de que se encarge de mover en contenido de micomponente/admin/components/libraries/tcpdf hacia url_de_tu_instalacion_joomla/libraries/tcpdf y se hace con el siguiente código:
<?php
  defined('_JEXEC') or die('Restricted access');

  jimport('joomla.filesystem.file');
  jimport('joomla.installer.installer');
  $path = JInstaller::getInstance()->getPath('extension_administrator');
  $src= $path.DS."libraries" ;
  $dst= JPATH_ROOT.DS."libraries" ;
  recurse_copy($src,$dst);

  function recurse_copy($src,$dst ){
    $dir = opendir($src);
    createIndexFolder($dst);
    if(is_resource($dir)){
      while(false !== ( $file = readdir($dir)) ) {
        if (( $file != '.' ) && ( $file != '..' )) {
          if ( is_dir($src .DS. $file) ) {
            recurse_copy($src .DS. $file,$dst .DS. $file);
          }else {
            if(JFile::exists($dst .DS. $file)){
              if(!JFile::delete($dst .DS. $file)){
                $app = JFactory::getApplication();
                $app -> enqueueMessage('Couldnt delete '.$dst .DS. $file);
              }
            }
            if(!JFile::move($src .DS. $file,$dst .DS. $file)){
              $app = JFactory::getApplication();
              $app -> enqueueMessage('Couldnt move '.$src .DS. $file.' to '.$dst .DS. $file);
            }
          }
        }
      }
      closedir($dir);
      if (is_dir($src)) JFolder::delete($src);
    } else {
      $app = JFactory::getApplication();
      $app -> enqueueMessage('Couldnt read dir '.$dir.' source '.$src);
    }
  }

  function createIndexFolder($path){
    if(JFolder::create($path)) {
      if(!JFile::exists($path .DS. 'index.html')){
        JFile::copy(JPATH_ROOT.DS.'components'.DS.'index.html', $path .DS. 'index.html');
      }
      return true;
    }
    return false;
  }
?>

Y cumpliendo todo lo anterior nuestro instalador se encargara de actualizar las fonts y contenido de TCPDF en las libraries de joomla quedando listo para el uso de nuestro componente e incluso para el uso de otros componentes o del sistema en general.

Comentarios

Entradas populares