Subversion Repositories eFlore/Applications.cel

Rev

Rev 3204 | Rev 3231 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

<?php
// declare(encoding='UTF-8');
/**
 * Service affichant les dernières photo publiques du CEL ouvrable sous forme de diaporama.
 * Encodage en entrée : utf8
 * Encodage en sortie : utf8
 *
 * Cas d'utilisation et documentation :
 * @link http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=AideCELWidgetPhoto
 *
 * Paramètres :
 * ===> extra = booléen (1 ou 0)  [par défaut : 1]
 * Affiche / Cache la vignette en taille plus importante au bas du widget.
 * ===> vignette = [0-9]+,[0-9]+  [par défaut : 4,3]
 * Indique le nombre de vignette par ligne et le nombre de ligne.
 *
 * @author    Jean-Pascal MILCENT <jpm@tela-botanica.org>
 * @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
 * @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
 * @version $Id$
 * @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
 */
class Saisie2 extends WidgetCommun {

  const DS = DIRECTORY_SEPARATOR;
  const SERVICE_DEFAUT = 'saisie';
  const LANGUE_DEFAUT = 'fr';
  const PROJET_DEFAUT = 'base';
  const WS_NOM = 'noms';
  const EFLORE_API_VERSION = '0.1';
  private $cel_url_tpl = null;
  /** Si spécifié, on ajoute une barre de navigation inter-applications */
  private $bar;
  //private $parametres_autorises = array('projet', 'type', 'langue', 'order');
  private $parametres_autorises = array(
      'projet' => 'projet',
      'type' => 'type',
      'langue' => 'langue',
      'order' => 'order'
  );
  /**
   * Méthode appelée par défaut pour charger ce widget.
   */
  public function executer() {
    $retour = null;
    // Pour la création de l'id du cache nous ne tenons pas compte du paramètre de l'url callback
    unset($this->parametres['callback']);
    extract($this->parametres);
    $this->bar = (isset($bar)) ? $bar : false;
    /* Le fichier Framework.php du Framework de Tela Botanica doit être appelé avant tout autre chose dans l'application.
     Sinon, rien ne sera chargé.
     L'emplacement du Framework peut varier en fonction de l'environnement (test, prod...). Afin de faciliter la configuration
     de l'emplacement du Framework, un fichier framework.defaut.php doit être renommé en framework.php et configuré pour chaque installation de
     l'application.
     Chemin du fichier chargeant le framework requis */
    $framework = dirname(__FILE__).'/framework.php';
    if (!file_exists($framework)) {
      $e = "Veuillez paramêtrer l'emplacement et la version du Framework dans le fichier $framework";
      trigger_error($e, E_USER_ERROR);
    } else {
      // Inclusion du Framework
      require_once $framework;
      // Ajout d'information concernant cette application
      Framework::setCheminAppli(__FILE__);// Obligatoire
      Framework::setInfoAppli(Config::get('info'));// Optionnel

    }
    $langue = (isset($langue)) ? $langue : self::LANGUE_DEFAUT;
    $this->langue = I18n::setLangue($langue);
    $this->parametres['langue'] = $langue;

    if (!isset($mode)) {
      $mode = self::SERVICE_DEFAUT;
    }
    if (!isset($projet)) {
      $this->parametres['projet'] = self::PROJET_DEFAUT;
    }

    $methode = $this->traiterNomMethodeExecuter($mode);
    if (method_exists($this, $methode)) {
      $retour = $this->$methode();
    } else {
      $this->messages[] = "Ce type de service '$methode' n'est pas disponible.";
    }

    $contenu = '';
    if (is_null($retour)) {
      $this->messages[] = 'La ressource demandée a retourné une valeur nulle.';
    } else {
      if (isset($retour['donnees'])) {
        $retour['donnees']['prod'] = ($this->config['parametres']['modeServeur'] == "prod");
        $retour['donnees']['bar'] = $this->bar;
        $retour['donnees']['url_base'] = sprintf($this->config['chemins']['baseURLAbsoluDyn'], '');
        $retour['donnees']['url_ws_annuaire'] = sprintf($this->config['chemins']['baseURLServicesAnnuaireTpl'], 'utilisateur/identite-par-courriel/');
        $retour['donnees']['url_ws_upload'] = $this->config['manager']['uploadUrl'];
        $retour['donnees']['authTpl'] = $this->config['manager']['authTpl'].'?projet='.$this->parametres['projet'].'&langue='.$this->parametres['langue'];
        $retour['donnees']['mode'] = $mode;
        $squelette = dirname(__FILE__).self::DS.'squelettes'.self::DS.$retour['squelette'].'.tpl.html';
        $contenu = $this->traiterSquelettePhp($squelette, $retour['donnees']);
      } else {
        $this->messages[] = 'Les données à transmettre au squelette sont nulles.';
      }
    }
    $this->envoyer($contenu);
  }


  private function executerSaisie() {
    $retour = array();
    $retour['squelette'] = 'saisie';
    $retour['donnees']['general'] = I18n::get('General');
    $retour['donnees']['aide'] = I18n::get('Aide');
    $retour['donnees']['observateur'] = I18n::get('Observateur');
    $retour['donnees']['observation'] = I18n::get('Observation');
    $retour['donnees']['widget'] = $this->rechercherProjet();
    return $retour;
  }

  /* Recherche si le projet existe sinon va chercher les infos de base */
  private function rechercherProjet() {
    // projet avec un squelette défini (et non juste un mot-clé d'observation)
    $estProjetDefini = true;
    $tab = array();
    $url = $this->config['manager']['celUrlTpl'].'?projet='.$this->parametres['projet'].'&langue='.$this->parametres['langue'];
    $json = $this->getDao()->consulter($url);
    if ($json == false) {
      $url = $this->config['manager']['celUrlTpl'].'?projet=base&langue='.$this->parametres['langue'];
      $json = $this->getDao()->consulter($url);
      $estProjetDefini = false;
    } else {
      $tab = $this->rechercherChampsSupp();
    }
    $tableau = json_decode($json, true);
    $tableau = $this->traiterParametres($estProjetDefini, $tableau[0]);
    $tableau['especes'] = $this->rechercherInfosEspeces($tableau);
    if ($tableau['milieux'] != "") {
      $tableau['milieux']= explode(";", $tableau['milieux']);
    } else {
      $tableau['milieux'] = array();
    }
    $tableau['chpSupp'] = $tab;
    return $tableau;
  }

  /* Recherche si un projet a des champs de saisie supplémentaire */
  private function rechercherChampsSupp() {
    $retour = array();
    $url = $this->config['manager']['celChpSupTpl'].'?projet='.$this->parametres['projet'].'&langue='.$this->parametres['langue'];
    $json = $this->getDao()->consulter($url);
    $retour = (array) json_decode($json, true);
    foreach ($retour['sauvagessupp']['champs-supp'] as $key => $chsup) {
      if (isset($chsup['fieldValues'])) {
        $retour['sauvagessupp']['champs-supp'][$key]['fieldValues'] = json_decode($chsup['fieldValues'], true);
        if (isset($retour['sauvagessupp']['champs-supp'][$key]['fieldValues']["listValue"])) {
          foreach($retour['sauvagessupp']['champs-supp'][$key]['fieldValues']["listValue"] as $list_value) {
            // Obtenir une liste de valeurs utilisables dans les attributs for id ou name par exemple
            $retour['sauvagessupp']['champs-supp'][$key]['fieldValues']['cleanListValue'][] = 'val-' . preg_replace('/[^A-Za-z0-9_\-]/', '',$this->remove_accents($list_value));
          }
        }
      }
      $retour['sauvagessupp']['champs-supp'][$key]['mandatory'] = intval($chsup['mandatory']);
    }
    return $retour;
  }

  private function remove_accents($string) {
    if ( !preg_match('/[\x80-\xff]/', $string) )
      return $string;

    $chars = array(
      // Decompositions for Latin-1 Supplement
      chr(195).chr(128) => 'A', chr(195).chr(129) => 'A',
      chr(195).chr(130) => 'A', chr(195).chr(131) => 'A',
      chr(195).chr(132) => 'A', chr(195).chr(133) => 'A',
      chr(195).chr(135) => 'C', chr(195).chr(136) => 'E',
      chr(195).chr(137) => 'E', chr(195).chr(138) => 'E',
      chr(195).chr(139) => 'E', chr(195).chr(140) => 'I',
      chr(195).chr(141) => 'I', chr(195).chr(142) => 'I',
      chr(195).chr(143) => 'I', chr(195).chr(145) => 'N',
      chr(195).chr(146) => 'O', chr(195).chr(147) => 'O',
      chr(195).chr(148) => 'O', chr(195).chr(149) => 'O',
      chr(195).chr(150) => 'O', chr(195).chr(153) => 'U',
      chr(195).chr(154) => 'U', chr(195).chr(155) => 'U',
      chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y',
      chr(195).chr(159) => 's', chr(195).chr(160) => 'a',
      chr(195).chr(161) => 'a', chr(195).chr(162) => 'a',
      chr(195).chr(163) => 'a', chr(195).chr(164) => 'a',
      chr(195).chr(165) => 'a', chr(195).chr(167) => 'c',
      chr(195).chr(168) => 'e', chr(195).chr(169) => 'e',
      chr(195).chr(170) => 'e', chr(195).chr(171) => 'e',
      chr(195).chr(172) => 'i', chr(195).chr(173) => 'i',
      chr(195).chr(174) => 'i', chr(195).chr(175) => 'i',
      chr(195).chr(177) => 'n', chr(195).chr(178) => 'o',
      chr(195).chr(179) => 'o', chr(195).chr(180) => 'o',
      chr(195).chr(181) => 'o', chr(195).chr(182) => 'o',
      chr(195).chr(182) => 'o', chr(195).chr(185) => 'u',
      chr(195).chr(186) => 'u', chr(195).chr(187) => 'u',
      chr(195).chr(188) => 'u', chr(195).chr(189) => 'y',
      chr(195).chr(191) => 'y',
      // Decompositions for Latin Extended-A
      chr(196).chr(128) => 'A', chr(196).chr(129) => 'a',
      chr(196).chr(130) => 'A', chr(196).chr(131) => 'a',
      chr(196).chr(132) => 'A', chr(196).chr(133) => 'a',
      chr(196).chr(134) => 'C', chr(196).chr(135) => 'c',
      chr(196).chr(136) => 'C', chr(196).chr(137) => 'c',
      chr(196).chr(138) => 'C', chr(196).chr(139) => 'c',
      chr(196).chr(140) => 'C', chr(196).chr(141) => 'c',
      chr(196).chr(142) => 'D', chr(196).chr(143) => 'd',
      chr(196).chr(144) => 'D', chr(196).chr(145) => 'd',
      chr(196).chr(146) => 'E', chr(196).chr(147) => 'e',
      chr(196).chr(148) => 'E', chr(196).chr(149) => 'e',
      chr(196).chr(150) => 'E', chr(196).chr(151) => 'e',
      chr(196).chr(152) => 'E', chr(196).chr(153) => 'e',
      chr(196).chr(154) => 'E', chr(196).chr(155) => 'e',
      chr(196).chr(156) => 'G', chr(196).chr(157) => 'g',
      chr(196).chr(158) => 'G', chr(196).chr(159) => 'g',
      chr(196).chr(160) => 'G', chr(196).chr(161) => 'g',
      chr(196).chr(162) => 'G', chr(196).chr(163) => 'g',
      chr(196).chr(164) => 'H', chr(196).chr(165) => 'h',
      chr(196).chr(166) => 'H', chr(196).chr(167) => 'h',
      chr(196).chr(168) => 'I', chr(196).chr(169) => 'i',
      chr(196).chr(170) => 'I', chr(196).chr(171) => 'i',
      chr(196).chr(172) => 'I', chr(196).chr(173) => 'i',
      chr(196).chr(174) => 'I', chr(196).chr(175) => 'i',
      chr(196).chr(176) => 'I', chr(196).chr(177) => 'i',
      chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij',
      chr(196).chr(180) => 'J', chr(196).chr(181) => 'j',
      chr(196).chr(182) => 'K', chr(196).chr(183) => 'k',
      chr(196).chr(184) => 'k', chr(196).chr(185) => 'L',
      chr(196).chr(186) => 'l', chr(196).chr(187) => 'L',
      chr(196).chr(188) => 'l', chr(196).chr(189) => 'L',
      chr(196).chr(190) => 'l', chr(196).chr(191) => 'L',
      chr(197).chr(128) => 'l', chr(197).chr(129) => 'L',
      chr(197).chr(130) => 'l', chr(197).chr(131) => 'N',
      chr(197).chr(132) => 'n', chr(197).chr(133) => 'N',
      chr(197).chr(134) => 'n', chr(197).chr(135) => 'N',
      chr(197).chr(136) => 'n', chr(197).chr(137) => 'N',
      chr(197).chr(138) => 'n', chr(197).chr(139) => 'N',
      chr(197).chr(140) => 'O', chr(197).chr(141) => 'o',
      chr(197).chr(142) => 'O', chr(197).chr(143) => 'o',
      chr(197).chr(144) => 'O', chr(197).chr(145) => 'o',
      chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe',
      chr(197).chr(148) => 'R',chr(197).chr(149) => 'r',
      chr(197).chr(150) => 'R',chr(197).chr(151) => 'r',
      chr(197).chr(152) => 'R',chr(197).chr(153) => 'r',
      chr(197).chr(154) => 'S',chr(197).chr(155) => 's',
      chr(197).chr(156) => 'S',chr(197).chr(157) => 's',
      chr(197).chr(158) => 'S',chr(197).chr(159) => 's',
      chr(197).chr(160) => 'S', chr(197).chr(161) => 's',
      chr(197).chr(162) => 'T', chr(197).chr(163) => 't',
      chr(197).chr(164) => 'T', chr(197).chr(165) => 't',
      chr(197).chr(166) => 'T', chr(197).chr(167) => 't',
      chr(197).chr(168) => 'U', chr(197).chr(169) => 'u',
      chr(197).chr(170) => 'U', chr(197).chr(171) => 'u',
      chr(197).chr(172) => 'U', chr(197).chr(173) => 'u',
      chr(197).chr(174) => 'U', chr(197).chr(175) => 'u',
      chr(197).chr(176) => 'U', chr(197).chr(177) => 'u',
      chr(197).chr(178) => 'U', chr(197).chr(179) => 'u',
      chr(197).chr(180) => 'W', chr(197).chr(181) => 'w',
      chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y',
      chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z',
      chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z',
      chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z',
      chr(197).chr(190) => 'z', chr(197).chr(191) => 's'
    );

    $string = strtr($string, $chars);

    return $string;
  }

  // remplace certains parametres définis en bd par les parametres définis dans l'url
  private function traiterParametres($estProjetDefini, $tableau) {
    $criteres = array('tag', 'motcle', 'projet', 'titre', 'logo');
    $criteresProjetNonDefini = array('commune', 'num_nom', 'referentiel');
    foreach($this->parametres as $nom_critere => $valeur_critere) {
      if (($estProjetDefini == false || $tableau['projet'] == "base") && in_array($nom_critere, $criteresProjetNonDefini)) {
        $tableau[$nom_critere] = $valeur_critere;
      } else if (in_array($nom_critere, $criteres)) {
        $tableau[$nom_critere] = $valeur_critere;
      }
    }
    return $tableau;
  }


  private function rechercherInfosEspeces( $infos_projets ) { //print_r($infos_projets);exit;
    $retour = array();
    $referentiel = $infos_projets['referentiel'];
    $urlWsNsTpl = $this->config['chemins']['baseURLServicesEfloreTpl'];
    $urlWsNs = sprintf( $urlWsNsTpl, self::EFLORE_API_VERSION, $referentiel, self::WS_NOM );
    $urlWsNsSansRef = sprintf( $urlWsNsTpl, self::EFLORE_API_VERSION, '{referentiel}', self::WS_NOM );
    $retour['url_ws_autocompletion_ns'] = $urlWsNs;
    $retour['url_ws_autocompletion_ns_tpl'] = $urlWsNsSansRef;
    $retour['ns_referentiel'] = $referentiel;

    if ( isset( $infos_projets['type_especes'] ) && 'fixe' === $infos_projets['type_especes']) {

      switch ( $infos_projets['type_especes'] ) {
        case "fixe" :
          $retour['especes'] = $this->chargerInfosTaxon( $infos_projets['referentiel'], $infos_projets['especes'] );
          break;
        case "referentiel" :
        case "liste" :
          $referentiel = $infos_projets['referentiel'];
          break;
      }
    } else if ( isset( $infos_projets['referentiel'] ) ) {
      $referentiel = $infos_projets['referentiel'];
      if ( isset($infos_projets['num_nom'] ) ) {
        $retour['especes'] = $this->chargerInfosTaxon( $infos_projets['referentiel'], $infos_projets['num_nom'] );
      }
    }

    $projetsAListeDeNoms = $this->transformerEnTableau( $this->config['projets']['liste_noms'] ) ;
    if ( in_array( $this->projet, $projetsAListeDeNoms ) && !$this->especeEstImposee() ) {
      $projetsAListeDeNomsSciEtVerna = $this->transformerEnTableau( $this->config['projets']['liste_noms_sci_et_verna'] );
      if ( in_array( $this->projet, $projetsAListeDeNomsSciEtVerna ) ) {
        $retour['taxons'] = $this->recupererListeNoms();
      } else {
        $retour['taxons'] = $this->recupererListeNomsSci();
      }
    }
    return $retour;
  }

  /**
   * Consulte un webservice pour obtenir des informations sur le taxon dont le
   * numéro nomenclatural est $num_nom (ce sont donc plutôt des infos sur le nom
   * et non le taxon?)
   * @param string|int $num_nom
   * @return array
   */
  protected function chargerInfosTaxon( $referentiel, $num_nom ) {
    $url_service_infos = sprintf( $this->config['chemins']['infosTaxonUrl'], $referentiel, $num_nom );
    $infos = json_decode( file_get_contents( $url_service_infos ) );
    // trop de champs injectés dans les infos espèces peuvent
    // faire planter javascript
    $champs_a_garder = array( 'id', 'nom_sci','nom_sci_complet', 'nom_complet',
        'famille','nom_retenu.id', 'nom_retenu_complet', 'num_taxonomique' );
    $resultat = array();
    $retour = array();
    if ( isset( $infos ) && !empty( $infos ) ) {
      $infos = (array) $infos;
      if ( isset( $infos['nom_sci'] ) && $infos['nom_sci'] != '' ) {
        $resultat = array_intersect_key( $infos, array_flip($champs_a_garder ) );
        $resultat['retenu'] = ( $infos['id'] == $infos['nom_retenu.id'] ) ? "true" : "false";
        $retour['espece_imposee'] = true;
        $retour['nn_espece_defaut'] = $nnEspeceImposee;
        $retour['nom_sci_espece_defaut'] = $resultat['nom_complet'];
        $retour['infos_espece'] = $this->array2js( $resultat, true );
      }
    }
    return $retour;
  }

  protected function getReferentielImpose() {
    $referentiel_impose = true;
    if (!empty($_GET['referentiel']) && $_GET['referentiel'] != "autre") {
      $this->ns_referentiel = $_GET['referentiel'];
    } else if (isset($this->configProjet['referentiel'])) {
      $this->ns_referentiel = $this->configProjet['referentiel'];
    } else if (isset($this->configMission['referentiel'])) {
      $this->ns_referentiel = $this->configMission['referentiel'];
    } else {
      $referentiel_impose = false;
    }
    return $referentiel_impose;
  }

  /**
   * Trie par nom français les taxons lus dans le fichier tsv
   */
  protected function recupererListeNomsSci() {
    $taxons = $this->recupererListeTaxon();
    if (is_array($taxons)) {
      $taxons = self::trierTableauMd($taxons, array('nom_fr' => SORT_ASC));
    }
    return $taxons;
  }

  /**
   * @TODO documenter
   * @return array
   */
  protected function recupererListeNoms() {
    $taxons = $this->recupererListeTaxon();
    $nomsAAfficher = array();
    $nomsSpeciaux = array();
    if (is_array($taxons)) {
      foreach ($taxons as $taxon) {
        $nomSciTitle = $taxon['nom_ret'].
        ($taxon['nom_fr'] != '' ? ' - '.$taxon['nom_fr'] : '' ).
        ($taxon['nom_fr_autre'] != '' ? ' - '.$taxon['nom_fr_autre'] : '' );
        $nomFrTitle = $taxon['nom_sel'].
        ($taxon['nom_ret'] != $taxon['nom_sel']? ' - '.$taxon['nom_ret'] : '' ).
        ($taxon['nom_fr_autre'] != '' ? ' - '.$taxon['nom_fr_autre'] : '' );

        if ($taxon['groupe'] == 'special') {
          $nomsSpeciaux[] = array(
              'num_nom' => $taxon['num_nom_sel'],
              'nom_a_afficher' => $taxon['nom_fr'],
              'nom_a_sauver' => $taxon['nom_sel'],
              'nom_title' => $nomSciTitle,
              'nom_type' => 'nom-special');
        } else {
          $nomsAAfficher[] = array(
              'num_nom' => $taxon['num_nom_sel'],
              'nom_a_afficher' => $taxon['nom_sel'],
              'nom_a_sauver' => $taxon['nom_sel'],
              'nom_title' => $nomSciTitle,
              'nom_type' => 'nom-sci');
          $nomsAAfficher[] = array(
              'num_nom' => $taxon['num_nom_sel'],
              'nom_a_afficher' => $taxon['nom_fr'],
              'nom_a_sauver' => $taxon['nom_fr'],
              'nom_title' => $nomFrTitle,
              'nom_type' => 'nom-fr');
        }
      }
      $nomsAAfficher = self::trierTableauMd($nomsAAfficher, array('nom_a_afficher' => SORT_ASC));
      $nomsSpeciaux = self::trierTableauMd($nomsSpeciaux, array('nom_a_afficher' => SORT_ASC));
    }
    return array('speciaux' => $nomsSpeciaux, 'sci-et-fr' => $nomsAAfficher);
  }

  /**
   * Lit une liste de taxons depuis un fichier tsv fourni
   */
  protected function recupererListeTaxon() {
    $taxons = array();
    if ($this->projet == 'missions-flore') {
      $fichier_tsv = dirname(__FILE__).self::DS.'configurations'.self::DS.$this->projet.'_'.$this->mission.'_taxons.tsv';
    } else {
      $fichier_tsv = dirname(__FILE__).self::DS.'configurations'.self::DS.$this->projet.'_taxons.tsv';
    }
    if (file_exists($fichier_tsv) && is_readable($fichier_tsv)) {
      $taxons = $this->decomposerFichierTsv($fichier_tsv);
    } else {
      $this->debug[] = "Impossible d'ouvrir le fichier '$fichier_tsv'.";
    }
    return $taxons;
  }

  /**
   * Découpe un fihcier tsv
   */
  protected function decomposerFichierTsv($fichier, $delimiter = "\t"){
    $header = null;
    $data = array();
    if (($handle = fopen($fichier, 'r')) !== FALSE) {
      while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE) {
        if (!$header) {
          $header = $row;
        } else {
          $data[] = array_combine($header, $row);
        }
      }
      fclose($handle);
    }
    return $data;
  }

  /**
   * Convertit un tableau PHP en Javascript - @WTF pourquoi ne pas faire un json_encode ?
   * @param array $array
   * @param boolean $show_keys
   * @return une portion de JSON représentant le tableau
   */
  protected function array2js($array,$show_keys) {
    $tableauJs = '{}';
    if (!empty($array)) {
      $total = count($array) - 1;
      $i = 0;
      $dimensions = array();
      foreach ($array as $key => $value) {
        if (is_array($value)) {
          $dimensions[$i] = array2js($value,$show_keys);
          if ($show_keys) {
            $dimensions[$i] = '"'.$key.'":'.$dimensions[$i];
          }
        } else {
          $dimensions[$i] = '"'.addslashes($value).'"';
          if ($show_keys) {
            $dimensions[$i] = '"'.$key.'":'.$dimensions[$i];
          }
        }
        if ($i == 0) {
          $dimensions[$i] = '{'.$dimensions[$i];
        }
        if ($i == $total) {
          $dimensions[$i].= '}';
        }
        $i++;
      }
      $tableauJs = implode(',', $dimensions);
    }
    return $tableauJs;
  }


}
?>