Subversion Repositories eFlore/Applications.moissonnage

Compare Revisions

No changes between revisions

Ignore whitespace Rev 1 → Rev HEAD

/trunk/scripts/modules/tuilage/tuilage.ini
New file
0,0 → 1,14
[carte]
carte.limite_ouest = -180
carte.limite_est = 180
carte.limite_sud = -85.051129
carte.limite_nord = 85.051129
 
rayon_terre = 6378137
zoom_minimal = 3
zoom_maximal = 13
taille_mailles_px = 32
 
[bdd]
eflore_table_mailles = "mailles_index"
eflore_champs_table = "zoom,axe,position,debut,fin"
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/scripts/modules/tuilage/Tuilage.php
New file
0,0 → 1,163
<?php
 
/**
* Exemple lancement:
* /opt/lampp/bin/php -d memory_limit=3500M ~/web/moissonnage/scripts/cli.php tuilage -a genererMaillage
*
* @author alex
*
*/
 
class Tuilage extends Script {
 
private $bdd = null;
private $resolution = 0;
private $resolutionInitiale = 0;
private $origine = 0;
private $longueurMaille;
 
public function executer() {
try {
$this->initialiserScript();
$cmd = $this->getParametre('a');
switch ($cmd) {
case 'genererMaillage' :
$this->genererTuilage();
break;
default :
throw new Exception("Erreur : la commande '{$cmd}' n'existe pas!");
}
} catch(Exception $e) {
$this->traiterErreur($e->getMessage());
}
}
private function initialiserScript() {
$fichierIni = $this->getScriptChemin().'tuilage.ini';
if (file_exists($fichierIni)) {
Config::charger($fichierIni);
} else {
$m = "Veuillez configurer le projet en créant le fichier '{$this->projetNom}.ini' ".
"dans le dossier du module de script du projet à partir du fichier '{$this->projetNom}.defaut.ini'.";
throw new Exception($m);
}
$this->longueurMaille = Config::get('taille_mailles_px');
$this->resolutionInitiale = 2 * M_PI * Config::get('rayon_terre') / 256;
$this->origine = 2 * M_PI * Config::get('rayon_terre') / 2.0;
}
private function genererTuilage() {
if (!$this->estTableCreee()) {
$this->creerStructureTable();
print("Table créée");
}
$niveauxZoom = range(Config::get('zoom_minimal'), Config::get('zoom_maximal'), 1);
foreach ($niveauxZoom as $zoom) {
print("Génération des mailles au niveau de zoom {$zoom}...\n");
$this->resolution = $this->resolutionInitiale / pow(2, $zoom);
$coordonneesLng = $this->calculerCoordonneesLimitesTuiles($zoom, 'lng');
$coordonneesLat = $this->calculerCoordonneesLimitesTuiles($zoom, 'lat');
print("mailles calculées\n");
$this->ajouterMaillesDansBdd($zoom, $coordonneesLng, $coordonneesLat);
}
}
private function estTableCreee() {
print("test table");
$tables = $this->getBdd()->recupererTous("SHOW TABLES FROM ".Config::get('bdd_nom'));
$table = Config::get('eflore_table_mailles');
for ($index = 0; $index < count($tables) && $tables[$index]['Tables_in_tb_eflore_test'] != $table; $index ++);
return $index < count($tables);
}
private function creerStructureTable() {
$table = Config::get('eflore_table_mailles');
print("Table {$table} non trouvée dans la base de données, création de sa structure...\n");
$requete =
"CREATE TABLE {$table} (".
"zoom TINYINT UNSIGNED NOT NULL,".
"axe ENUM('lat','lng') NOT NULL,".
"position SMALLINT UNSIGNED NOT NULL,".
"debut DECIMAL(9,6) NOT NULL,".
"fin DECIMAL(9,6) NOT NULL,".
"PRIMARY KEY (zoom, axe, position)".
") ENGINE=MyISAM, CHARACTER SET utf8";
$this->getBdd()->requeter($requete);
$requete = "ALTER TABLE {$table} ADD INDEX (debut), ADD INDEX(fin)";
$this->getBdd()->requeter($requete);
}
private function calculerCoordonneesLimitesTuiles($zoom, $axe) {
$variableConfigLimite = $axe == 'lng' ? 'carte.limite_est' : 'carte.limite_nord';
$limiteCalcul = Config::get($variableConfigLimite);
$nombrePixels = pow(2, $zoom+8);
$tailleTableau = $nombrePixels / $this->longueurMaille;
$valeurs = array();
for ($index = 0; $index <= $tailleTableau; $index ++) {
$valeur = $this->convertirPixelEnLatLng($index * $this->longueurMaille, $axe);
$valeurs[] = $this->convertirFloatToString($valeur);
}
return $valeurs;
}
private function convertirPixelEnLatLng($pixel, $axe) {
$coord_metrique = $pixel * $this->resolution - $this->origine;
$coord_lnglat = ($coord_metrique / $this->origine) * 180.0;
if ($axe == 'lat') {
$coord_lnglat = 180 / M_PI * (2 * atan(exp($coord_lnglat * M_PI / 180.0)) - M_PI / 2.0);
}
return $coord_lnglat;
}
private function ajouterMaillesDansBdd($zoom, $coordonneesLng, $coordonneesLat) {
$table = Config::get('eflore_table_mailles');
$nomsChamps = Config::get('eflore_champs_table');
$this->getBdd()->requeter("DELETE FROM {$table} WHERE zoom=$zoom");
$insertions = array();
$j = 10000;
if (count($coordonneesLng) > $j) {
for ($i=0; $i < count($coordonneesLng); $i=$i+$j) {
$insertions = array();print($i." ".$j." ");
if ($i+$j > count($coordonneesLng)) {
$k =count($coordonneesLng) - 1;
} else {
$k = $i+$j;
} print_r($k."\n");
for ($index = $i; $index < $k; $index ++) {
$insertions[] = "({$zoom},'lng',{$index},".$coordonneesLng[$index].",".$coordonneesLng[$index+1].")";
}
for ($index = $i; $index < $k; $index ++) {
$insertions[] = "({$zoom},'lat',{$index},".$coordonneesLat[$index].",".$coordonneesLat[$index+1].")";
}
$requete = "INSERT INTO {$table}({$nomsChamps}) VALUES ".implode(',', $insertions);
$this->getBdd()->requeter($requete);
}
} else {
for ($index = 0; $index < count($coordonneesLng)-1; $index ++) {
$insertions[] = "({$zoom},'lng',{$index},".$coordonneesLng[$index].",".$coordonneesLng[$index+1].")";
}
for ($index = 0; $index < count($coordonneesLat)-1; $index ++) {
$insertions[] = "({$zoom},'lat',{$index},".$coordonneesLat[$index].",".$coordonneesLat[$index+1].")";
}
$requete = "INSERT INTO {$table}({$nomsChamps}) VALUES ".implode(',', $insertions);
$this->getBdd()->requeter($requete);
}
}
private function getBdd() {
if (is_null($this->bdd)) {
$this->bdd = new Bdd();
}
return $this->bdd;
}
private function convertirFloatToString($float) {
return str_replace(',', '.', strval($float));
}
}
 
?>
/trunk/scripts/modules/maillage_projet/sources/baznat.ini
New file
0,0 → 1,5
[champs]
 
tbl.champ_longitude = "longitude"
tbl.champ_latitude = "latitude"
tbl.champ_id = "guid"
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/scripts/modules/maillage_projet/sources/sophy.ini
New file
0,0 → 1,5
[champs]
 
tbl.champ_longitude = "lieu_station_longitude"
tbl.champ_latitude = "lieu_station_latitude"
tbl.champ_id = "guid"
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/scripts/modules/maillage_projet/MaillageProjet.php
New file
0,0 → 1,195
<?php
 
/**
* Exemple lancement:
* /opt/lampp/bin/php -d memory_limit=3500M ~/web/moissonnage/scripts/cli.php maillage_projet
* -a source=nom_source
*
* @author alex
*
*/
 
class MaillageProjet extends Script {
private $nomProjet = 'maillage_projet';
private $nomSource = '';
private $bdd = null;
private $tableRequetage = '';
private $mailles = array();
private $points = array();
public function executer() {
try {
$this->initialiserScript();
$cmd = $this->getParametre('a');
$parametre = explode('=', $cmd);
if (count($parametre) != 2 && $parametre[0] != 'source') {
throw new Exception("Parametre passé incorrect : attendu source=nom_de_la_source\n");
} else {
if (!$this->estSourceDisponible($parametre[1])) {
$sourcesDispo = Config::get('sources_disponibles');
$message =
"Erreur lors de l'éxécution du script : la soruce demandée n'est pas disponible.\n".
"Les sources dont le maillage est réalisable sont les suivantes : {$sourcesDispo}.\n";
throw new Exception($message);
} else {
$this->nomSource = $parametre[1];
$this->chargerConfigurationSource($parametre[1]);
$this->tableRequetage = $parametre[1].Config::get('suffixe_table_interrogation');
$this->genererMaillage();
}
}
} catch(Exception $e) {
$this->traiterErreur($e->getMessage());
}
}
private function initialiserScript() {
$fichierIni = $this->getScriptChemin().'maillage_projet.ini';
if (file_exists($fichierIni)) {
Config::charger($fichierIni);
} else {
$m = "Veuillez configurer le projet en créant le fichier '{$this->nomProjet}.ini' ".
"dans le dossier du module de script du projet à partir du fichier '{$this->nomProjet}.defaut.ini'.";
throw new Exception($m);
}
}
private function estSourceDisponible($nomSource) {
$sourcesDispo = explode(',', Config::get('sources_disponibles'));
return (in_array($nomSource, $sourcesDispo));
}
private function chargerConfigurationSource($nomSource) {
$fichierIni = $this->getScriptChemin()."sources".DIRECTORY_SEPARATOR."{$nomSource}.ini";
if (file_exists($fichierIni)) {
Config::charger($fichierIni);
} else {
$m = "Veuillez configurer les champs specifiques à la source en créant le fichier ".
"'{$nomSource}.ini' dans le dossier sources de script du projet {$this->nomProjet}.";
throw new Exception($m);
}
}
private function genererMaillage() {
if (!$this->estTableCreee()) {
$this->creerStructureTable();
}
$zoomMinimal = Config::get('zoom_minimal');
$niveauxZoom = range($zoomMinimal, Config::get('zoom_maximal'), 1);
foreach ($niveauxZoom as $zoom) {
print("Génération des mailles au niveau de zoom {$zoom}...\n");
if ($zoom == $zoomMinimal) {
$this->initialiserMailles();
$this->genererMaillesPourZoomMinimal();
} else {
$this->mailles->redecouperMailles();
$this->ajouterMaillesDansBdd();
}
}
}
private function estTableCreee() {
$tables = $this->getBdd()->recupererTous("SHOW TABLES FROM ".Config::get('bdd_nom'));
$tableInsertion = 'mailles_'.$this->nomSource;
for ($index = 0; $index < count($tables) && $tables[$index]['Tables_in_tb_eflore'] != $tableInsertion;
$index ++);
return $index < count($tables);
}
private function creerStructureTable() {
$tableInsertion = 'mailles_'.$this->nomSource;
print("Table {$tableInsertion} non trouvée dans la base de données, création de sa structure...\n");
$requete =
"CREATE TABLE {$tableInsertion} (".
"code_maille VARCHAR(25) NOT NULL PRIMARY KEY,".
"zoom TINYINT UNSIGNED NOT NULL,".
"position_latitude SMALLINT UNSIGNED NOT NULL,".
"position_longitude SMALLINT UNSIGNED NOT NULL,".
"limite_sud DECIMAL(9,6) NOT NULL,".
"limite_est DECIMAL(9,6) NOT NULL,".
"limite_nord DECIMAL(9,6) NOT NULL,".
"limite_ouest DECIMAL(9,6) NOT NULL,".
"nombre_sites MEDIUMINT UNSIGNED NOT NULL,".
"nombre_observations MEDIUMINT UNSIGNED NOT NULL".
") ENGINE=MyISAM, CHARACTER SET utf8";
$this->getBdd()->requeter($requete);
$requete = "ALTER TABLE {$tableInsertion} ADD INDEX bbox(zoom, limite_sud, ".
"limite_nord, limite_ouest, limite_est)";
$this->getBdd()->requeter($requete);
}
private function initialiserMailles() {
$limitesEspaceMaillage = $this->recupererExtremesCoordonnees();
$this->recupererIndexMailles($limitesEspaceMaillage, Config::get('zoom_minimal'));
}
private function recupererExtremesCoordonnees() {
$champLongitude = Config::get('tbl.champ_longitude');
$champLatitude = Config::get('tbl.champ_latitude');
$requete = "SELECT Min({$champLongitude}) AS lng_min, Max({$champLongitude}) AS lng_max, ".
"Min({$champLatitude}) AS lat_min, Max({$champLatitude}) AS lat_max FROM {$this->tableRequetage}";
$limites = $this->getBdd()->recuperer($requete);
return $limites;
}
private function getBdd() {
if (is_null($this->bdd)) {
$this->bdd = new Bdd();
}
return $this->bdd;
}
private function recupererIndexMailles($limites, $zoom) {
$bbox = array(
'sud' => $limites['lat_min'],
'ouest' => $limites['lng_min'],
'est' => $limites['lng_max'],
'nord' => $limites['lat_max']
);
$this->mailles = new Maillage($bbox, $zoom);
$this->mailles->genererMaillesVides();
}
private function genererMaillesPourZoomMinimal() {
$this->points = $this->recupererPoints();
$this->mailles->ajouterPoints($this->points);
$this->ajouterMaillesDansBdd();
}
private function recupererPoints() {
print("Récupération des points dans la base de données...\n");
$champLongitude = Config::get('tbl.champ_longitude');
$champLatitude = Config::get('tbl.champ_latitude');
$id = Config::get('tbl.champ_id');
$requete = "SELECT COUNT({$id}) AS observations, {$champLatitude} AS latitude, {$champLongitude} ".
"AS longitude FROM {$this->tableRequetage} GROUP BY {$champLongitude},{$champLatitude}";
$points = $this->getBdd()->recupererTous($requete);
return $points;
print("Points chargés\n");
}
private function ajouterMaillesDansBdd() {
$aInserer = $this->mailles->formaterPourInsertionBdd();
$champsTable = Config::get('champs_table_mailles');
$tableInsertion = 'mailles_'.$this->nomSource;
$ordresInsertion = array();
$this->getBdd()->requeter("DELETE FROM {$tableInsertion} WHERE zoom={$aInserer[0]['zoom']}");
foreach ($aInserer as $ligne) {
$codeMaille = $this->nomSource.'.'.$ligne['zoom'].'-'.$ligne['indexLat'].'-'.$ligne['indexLng'];
$sql = "('{$codeMaille}',{$ligne['zoom']},{$ligne['indexLng']},{$ligne['indexLat']},".
"{$ligne['ouest']},{$ligne['sud']},{$ligne['est']},{$ligne['nord']},".
"{$ligne['points']},{$ligne['observations']})";
$ordresInsertion[] = $sql;
}
$requete = "INSERT INTO {$tableInsertion} ({$champsTable}) VALUES ".implode(',', $ordresInsertion);
$this->getBdd()->requeter($requete);
}
}
 
?>
/trunk/scripts/modules/maillage_projet/maillage_projet.ini
New file
0,0 → 1,10
[database]
 
table_index_mailles = "mailles_index"
suffixe_table_interrogation = "_tapir"
sources_disponibles = "sophy,baznat"
champs_table_mailles = "code_maille,zoom,position_longitude,position_latitude,limite_ouest,limite_sud,limite_est,limite_nord,nombre_sites,nombre_observations"
 
origine = 20037508.342789244
zoom_minimal = 3
zoom_maximal = 13
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/scripts/configurations/config.defaut.ini
New file
0,0 → 1,42
; Encodage : UTF-8
; +------------------------------------------------------------------------------------------------------+
; Info sur l'application
info.nom = Scripts de tests
; Abréviation de l'application
info.abr = SCRIPTS
; Version du Framework nécessaire au fonctionnement de cette application
info.framework.version = 0.3
; Encodage de l'application
encodage_appli = "UTF-8"
; Chemin de l'application (pour l'utiliser dans ce fichier)
chemin_scripts = "php:Framework::getCheminAppli()"
; +------------------------------------------------------------------------------------------------------+
; Débogage
; Indique si oui ou non on veut afficher le débogage.
debogage = true
; Indique si oui ou non on veut lancer le chronométrage
chronometrage = false
 
+------------------------------------------------------------------------------------------------------+
; Paramètrage de la base de données.
; bdd_abstraction : abstraction de la base de données.
; bdd_protocole : Protocole de la base de données.
; bdd_serveur : Nom du serveur de bases de données.
; bdd_utilisateur : Nom de l'utilisateur de la base de données.
; bdd_mot_de_passe : Mot de passe de l'utilisateur de la base de données.
; bdd_nom : Nom de la base de données principale.
; bdd_encodage : Encodage de la base de données principale. Normalement le même que l'application mais au format base de
; données : voir ici : http://dev.mysql.com/doc/refman/5.0/en/charset-charsets.html
; et là: http://www.postgresql.org/docs/8.1/static/multibyte.html pour les correspondances
bdd_abstraction = pdo
bdd_protocole = mysql
bdd_serveur = localhost
bdd_utilisateur = ""
bdd_mot_de_passe = ""
bdd_nom = "tb_eflore_test"
bdd_encodage = "utf8"
 
 
; Dossier de base contenant les données d'eFlore (Fichiers TSV et SQL)
dossierDonneesEflore = "/home/telabotap/www/eflore/donnees/"
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/scripts/configurations
New file
Property changes:
Added: svn:ignore
+config.ini
/trunk/scripts/framework.defaut.php
New file
0,0 → 1,6
<?php
// Inclusion du Framework
// Renomer ce fichier en "framework.php"
// Indiquer ci-dessous le chemin absolu vers le fichier autoload.inc.php de la bonne version du Framework
require_once '/home/www/commun/framework/0.3/Framework.php';
?>
/trunk/scripts/bibliotheque/Maillage.php
New file
0,0 → 1,228
<?php
 
 
class Maillage {
private $bbox;
private $zoom;
private $indexLongitude;
private $indexLatitude;
private $mailles;
private $origine;
private $bdd = null;
public function __construct($bbox, $zoom) {
$this->bbox = $bbox;
$this->zoom = $zoom;
$this->indexLongitude = array();
$this->indexLatitude = array();
$this->mailles = array();
$this->origine = Config::get('origine');
}
public function __destruct() {
while (count($this->indexLatitude) > 0) {
array_pop($this->indexLatitude);
}
while (count($this->indexLongitude) > 0) {
array_pop($this->indexLongitude);
}
while (count($this->mailles) > 0) {
array_pop($this->mailles);
}
unset($this);
}
public function genererMaillesVides() {
$this->recupererIndexMaillesDansBbox();
foreach ($this->indexLatitude as $indexLat => $intervalleLat) {
$ligne = array();
foreach ($this->indexLongitude as $indexLng => $intervalleLng) {
$ligne[] = new Maille($intervalleLat[0], $intervalleLng[0], $intervalleLat[1],
$intervalleLng[1], $indexLat, $indexLng);
}
$this->mailles[] = $ligne;
}
}
private function recupererIndexMaillesDansBbox() {
$tableIndex = Config::get('table_index_mailles');
$requete =
"SELECT axe, position, debut, fin FROM {$tableIndex} WHERE zoom={$this->zoom} AND (".
"(axe='lat' AND debut<{$this->bbox['nord']} AND fin>{$this->bbox['sud']}) ".
"OR (axe='lng' AND debut<{$this->bbox['est']} AND fin>{$this->bbox['ouest']})".
") ORDER BY axe, position";
$indexMailles = $this->getBdd()->recupererTous($requete);
foreach ($indexMailles as $index) {
if ($index['axe'] == 'lng') {
$this->indexLongitude[$index['position']] = array($index['debut'], $index['fin']);
} else {
$this->indexLatitude[$index['position']] = array($index['debut'], $index['fin']);
}
}
}
private function getBdd() {
if (is_null($this->bdd)) {
$this->bdd = new Bdd();
}
return $this->bdd;
}
public function ajouterPoints($points) {
foreach ($points as $point) {
$longitude = $point['longitude'];
$latitude = $point['latitude'];
list($indexLongitude, $indexLatitude) = $this->rechercherIndexMaille($longitude, $latitude);
$this->mailles[$indexLatitude][$indexLongitude]->ajouterPoint($point);
}
}
private function rechercherIndexMaille($longitude, $latitude) {
$indexLatitude = 0;
$indexLongitude = 0;
while ($indexLatitude < count($this->indexLatitude) - 1
&& $this->mailles[$indexLatitude][0]->getLatitudeNord() < $latitude) {
$indexLatitude ++;
}
while ($indexLongitude < count($this->indexLongitude) - 1
&& $this->mailles[$indexLatitude][$indexLongitude]->getLongitudeEst() < $longitude) {
$indexLongitude ++;
}
return array($indexLongitude, $indexLatitude);
}
 
public function formaterPourInsertionBdd() {
$mailles_resume = array();
foreach ($this->mailles as $ligne) {
foreach ($ligne as $maille) {
if ($maille->getNombrePoints() > 0) {
$mailles_resume[] = array(
'zoom' => $this->zoom,
'sud' => $maille->getLatitudeSud(),
'ouest' => $maille->getLongitudeOuest(),
'nord' => $maille->getLatitudeNord(),
'est' => $maille->getLongitudeEst(),
'indexLat' => $maille->getIndexLatitude(),
'indexLng' => $maille->getIndexLongitude(),
'points' => $maille->getNombrePoints(),
'observations' => $maille->getNombreObservations()
);
}
}
}
return $mailles_resume;
}
private function formaterPourQuadtree() {
$mailles_resume = array();
foreach ($this->mailles as $ligne) {
foreach ($ligne as $maille) {
if ($maille->getNombrePoints() > 0) {
$mailles_resume[] = array(
'zoom' => $this->zoom,
'sud' => $maille->getLatitudeSud(),
'ouest' => $maille->getLongitudeOuest(),
'nord' => $maille->getLatitudeNord(),
'est' => $maille->getLongitudeEst(),
'indexLat' => $maille->getIndexLatitude(),
'indexLng' => $maille->getIndexLongitude(),
'points' => $maille->getPoints()
);
}
}
}
return $mailles_resume;
}
public function redecouperMailles() {
$mailles = $this->formaterPourQuadtree();
$this->viderMailles();
while (count($mailles)>0) {
$nouvellesMailles = $this->genererMaillesParQuadtree($mailles[count($mailles)-1]);
foreach ($nouvellesMailles as $maille) {
$this->ajouterMaille($maille);
}
array_pop($mailles);
}
$this->zoom += 1;
}
private function viderMailles() {
while (count($this->indexLatitude) > 0) {
array_pop($this->indexLatitude);
}
while (count($this->indexLongitude) > 0) {
array_pop($this->indexLongitude);
}
while (count($this->mailles) > 0) {
array_pop($this->mailles);
}
}
private function genererMaillesParQuadtree(& $maille) {
$ouest = $maille['ouest'];
$est = $maille['est'];
$sud = $maille['sud'];
$nord = $maille['nord'];
$indexLat = $maille['indexLat'];
$indexLng = $maille['indexLng'];
$milieuLongitude = $this->convertirFloatToString(($ouest + $est)/2);
$milieuLatitude = $this->calculerMilieuLatitudes($sud, $nord);
// sens des mailles : NordOuest, NordEst, SudOuest, SudEst
$mailles = array();
$mailles[] = new Maille($milieuLatitude, $ouest, $nord, $milieuLongitude, $indexLat*2, $indexLng*2);
$mailles[] = new Maille($milieuLatitude, $milieuLongitude, $nord, $est, $indexLat*2, $indexLng*2+1);
$mailles[] = new Maille($sud, $ouest, $milieuLatitude, $milieuLongitude, $indexLat*2+1, $indexLng*2);
$mailles[] = new Maille($sud, $milieuLongitude, $milieuLatitude, $est, $indexLat*2+1, $indexLng*2+1);
$this->deplacerPoints($maille, $mailles);
return $mailles;
}
private function calculerMilieuLatitudes($latitudeSud, $latitudeNord) {
$ySud = log(tan((90 + $latitudeSud) * M_PI / 360.0 )) / (M_PI / 180.0) * ($this->origine/180.0);
$yNord = log(tan((90 + $latitudeNord) * M_PI / 360.0 )) / (M_PI / 180.0) * ($this->origine/180.0);
$yMilieu = ($ySud+$yNord) / 2;
$latitude = ($yMilieu / $this->origine) * 180.0;
$latitude = 180 / M_PI * (2 * atan(exp($latitude * M_PI / 180.0)) - M_PI / 2.0);
return $this->convertirFloatToString($latitude);
}
private function deplacerPoints(& $maille, & $sousMailles) {
$nombrePoints = count($maille['points']);
for ($index = 0; $index < $nombrePoints; $index ++) {
$position = ($maille['points'][$index]['latitude']>=$sousMailles[0]->getLatitudeSud()) ? 0 : 2;
$position += ($maille['points'][$index]['longitude']<$sousMailles[$position]->getLongitudeEst()) ? 0 : 1;
$sousMailles[$position]->ajouterPoint($maille['points'][$index]);
}
}
private function ajouterMaille($maille) {
$indexLat = $maille->getIndexLatitude();
$indexLng = $maille->getIndexLongitude();
if (!isset($this->indexLongitude[$indexLng])) {
$this->indexLongitude[$indexLng] = array($maille->getLongitudeOuest(), $maille->getLongitudeEst());
$this->mailles[$indexLng] = array();
}
if (!isset($this->indexLongitude[$indexLat])) {
$this->indexLatitude[$indexLat] = array($maille->getLatitudeSud(), $maille->getLatitudeNord());
}
$this->mailles[$indexLng][$indexLat] = $maille;
}
private function convertirFloatToString($float) {
return str_replace(',', '.', strval($float));
}
}
 
?>
/trunk/scripts/bibliotheque/Maille.php
New file
0,0 → 1,76
<?php
 
class Maille {
private $latitudeSud;
private $longitudeOuest;
private $latitudeNord;
private $longitudeEst;
private $indexLatitude;
private $indexLongitude;
private $points = array();
private $observations = array();
public function __construct($sud, $ouest, $nord, $est, $indexLat, $indexLng) {
$this->latitudeSud = $sud;
$this->longitudeOuest = $ouest;
$this->latitudeNord = $nord;
$this->longitudeEst = $est;
$this->indexLatitude = $indexLat;
$this->indexLongitude = $indexLng;
}
public function ajouterPoint($point) {
$this->points[] = $point;
$this->observations[] = $point['observations'];
}
public function getLatitudeNord() {
return $this->latitudeNord;
}
public function getLongitudeOuest() {
return $this->longitudeOuest;
}
public function getLatitudeSud() {
return $this->latitudeSud;
}
public function getLongitudeEst() {
return $this->longitudeEst;
}
public function getIndexLatitude() {
return $this->indexLatitude;
}
public function getIndexLongitude() {
return $this->indexLongitude;
}
public function getPoints() {
return $this->points;
}
public function getNombrePoints() {
return count($this->points);
}
public function getNombreObservations() {
return array_sum($this->observations);
}
public function getPoint($index = 0) {
return (!isset($this->points[$index])) ? NULL : $this->points[$index];
}
public function totalNonNul() {
return count($this->points) > 0;
}
}
 
?>
/trunk/scripts/cli.php
New file
0,0 → 1,37
<?php
// Encodage : UTF-8
// +-------------------------------------------------------------------------------------------------------------------+
/**
* Initialise le chargement et l'exécution des scripts
*
* Lancer ce fichier en ligne de commande avec :
* <code>/opt/lampp/bin/php cli.php mon_script -a test</code>
*
//Auteur original :
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @author Delphine CAUQUIL <delphine@tela-botanica.org>
* @copyright Tela-Botanica 1999-2008
* @licence GPL v3 & CeCILL v2
* @version $Id$
*/
// +-------------------------------------------------------------------------------------------------------------------+
 
// Le fichier Framework.php du Framework de Tela Botanica doit être appelée avant tout autre chose dans l'application.
// Sinon, rien ne sera chargé.
// Chemin du fichier chargeant le framework requis
$framework = dirname(__FILE__).DIRECTORY_SEPARATOR.'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'));
 
// Initialisation et lancement du script appelé en ligne de commande
Cli::executer();
}
?>
/trunk/scripts
New file
Property changes:
Added: svn:ignore
+framework.php
/trunk/services/modules/0.1/Projets.php
New file
0,0 → 1,175
<?php
 
 
class Projets extends RestService {
 
private $parametres = array();
private $ressources = array();
private $squeletteDossier = '';
private $cache;
public function __construct() {
$this->squeletteDossier = dirname(__FILE__).DIRECTORY_SEPARATOR;
}
 
public function consulter($ressources, $parametres) {
$resultat = '';
$reponseHttp = new ReponseHttp();
try {
$this->initialiserRessourcesEtParametres($ressources, $parametres);
$resultat = $this->traiterRessources();
$reponseHttp->setResultatService($resultat);
} catch (Exception $e) {
$reponseHttp->ajouterErreur($e);
}
$reponseHttp->emettreLesEntetes();
$corps = $reponseHttp->getCorps();
return $corps;
}
private function initialiserRessourcesEtParametres($ressources, $parametres) {
$this->ressources = $ressources;
$this->parametres = $parametres;
}
private function traiterRessources() {
$retour = '';
if ($this->avoirRessources()) {
if ($this->avoirRessourceService()) {
$retour = $this->initialiserService();
}
}
return $retour;
}
private function avoirRessources() {
$presenceDeRessources = false;
if (isset($this->ressources) && count($this->ressources) > 0) {
$presenceDeRessources = true;
} else {
$message = "Accès au service refusé : aucune ressource indiquée.\n"
. "Veuillez indiquer au moins une source de données à interroger"
. " et le type d'informations a renvoyer.";
$code = RestServeur::HTTP_CODE_MAUVAISE_REQUETE;
throw new Exception($message, $code);
}
return $presenceDeRessources;
}
private function chargerConfiguration($nomParametre) {
$tableau = array();
$tableauPartiel = explode(',', Config::get($nomParametre));
$tableauPartiel = array_map('trim', $tableauPartiel);
foreach ($tableauPartiel as $champ) {
if (strpos($champ, '=') === false) {
$tableau[] = $champ;
} else {
list($cle, $val) = explode('=', $champ);
$clePropre = trim($cle);
$valeurPropre = trim($val);
$tableau[$clePropre] = $valeurPropre;
}
}
return $tableau;
}
public static function chargerConfigurationSource($nomSource) {
$chemin = Config::get('chemin_configurations')."config_$nomSource.ini";
Config::charger($chemin);
}
private function chargerClasse($classe) {
if (class_exists($classe)) {
return null;
}
$cheminBiblio = Config::get('chemin_bibliotheque');
$chemins = array();
$chemins[] = $this->squeletteDossier;
$chemins[] = $this->squeletteDossier.'commun' .DIRECTORY_SEPARATOR;
$chemins[] = $this->squeletteDossier.'sources'.DIRECTORY_SEPARATOR;
$chemins[] = $cheminBiblio;
$chemins[] = $cheminBiblio.'robots'.DIRECTORY_SEPARATOR;
foreach ($chemins as $chemin) {
$chemin = $chemin.$classe.'.php';
if (file_exists($chemin)) {
require_once $chemin;
break;
}
}
}
private function avoirRessourceService() {
$presenceRessourceService = false;
$servicesDispo = $this->chargerConfiguration('services_dispo');
if (isset($this->ressources[0])) {
$service = $this->ressources[0];
if (in_array($service, $servicesDispo)) {
$presenceRessourceService = true;
} else {
$message = "La service demandé '$service' n'est pas disponible !\n"
. "Les services disponibles sont : ".implode(', ', $servicesDispo);
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE;
throw new Exception($message, $code);
}
} else {
$message = "Vous n'avez pas indiqué de service !\n"
. "Les services disponibles sont : ".implode(', ', $servicesDispo);
$code = RestServeur::HTTP_CODE_MAUVAISE_REQUETE;
throw new Exception($message, $code);
}
return $presenceRessourceService;
}
 
private function initialiserService() {
$nomService = 'commun';
$classe = $this->obtenirNomClasseService($nomService);
$chemins = array();
$chemins[] = $this->squeletteDossier.'commun'.DIRECTORY_SEPARATOR.'Commun.php';
// php5.3 : Enregistrement en première position des autoload de la méthode gérant les classes des services
if (phpversion() < 5.3) {
spl_autoload_register(array($this, 'chargerClasse'));
} else {
spl_autoload_register(array($this, 'chargerClasse'), true , true);
}
$retour = '';
$service = null;
foreach ($chemins as $chemin) {
if (file_exists($chemin)) {
$service = new $classe($this->getBdd());
$ressourcesPourService = $this->filtrerRessourcesPourService();
$this->cache = new CacheMoissonnage($service, $nomService,
Config::get('cache'));
$retour = $this->cache->consulter($ressourcesPourService, $this->parametres);
if (get_class($retour) == 'Exception') {
throw new Exception($retour->getMessage(), RestServeur::HTTP_CODE_MAUVAISE_REQUETE);
}
}
}
if (is_null($service)) {
$message = "Le service demandé '{$nomService}' n'existe pas !";
$code = RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE;
throw new Exception($message, $code);
}
return $retour;
}
private function obtenirNomClasseService($mot) {
$classeNom = str_replace(' ', '', ucwords(strtolower(str_replace('-', ' ', $mot))));
return $classeNom;
}
private function filtrerRessourcesPourService() {
return $this->ressources;
}
}
 
?>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/trunk/services/modules/0.1/commun/Commun.php
New file
0,0 → 1,404
<?php
 
/**
*
* Classe principale du web service qui peut traiter des requetes provenant d'un navigateur web
* (stations dans bbox ou observations sur un point), ou d'un client SIG via appel au protocole/service WFS
* (demande d'observations par stations selon des filtres optionnels). Le web service analyse et verifie
* les parametres de l'URL de la requete qu'il recoit. S'ils sont tous valides, il va appeler une autre classe
* pour recuperer les informations demandees dans les differentes sources de donnees.
* Les donnees recuperees sont ensuite combinees si plusieurs sources sont demandees et mises en forme
* au format de sortie. Les formats de sortie utilises sont le GeoJSON (extension de JSON pour les donnees
* geographiques) en destination des navigateurs web et le GML adapte au service WFS pour les clients SIG.
* Dans le cas ou des erreurs sont levees, le web service renvoie un message d'erreur expliquant le probleme
* recnontre dans son fonctionnement.
*
*
* @package framework-0.4
* @author Alexandre GALIBERT <alexandre.galibert@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 2013 Tela Botanica (accueil@tela-botanica.org)
*
*/
 
class Commun {
private $parametres = array();
private $ressources = array();
private $nomSource = '';
private $nomService = '';
private $verificateur = null;
private $parametresRecherche = null;
private $retour = array();
const MIME_WFS = 'text/xml';
public function consulter($ressources, $parametres) {
$this->recupererRessourcesEtParametres($ressources, $parametres);
$retour = null;
if (in_array("wfs", $ressources)) {
$retour = $this->traiterRequeteWfs();
} else {
$retour = $this->traiterRequeteNavigateur();
}
return $retour;
}
/*********************************************/
// Verification parametres URL non-WFS
private function traiterRequeteWfs() {
$retour = null;
try {
$this->parametresRecherche = new StdClass();
$this->traiterParametreOperation();
if ($this->parametresRecherche->operation != 'GetCapabilities') {
$this->traiterParametreSource();
}
if ($this->parametresRecherche->operation == 'GetFeature') {
$retour = $this->getFeature();
} else {
$formateurWfs = new FormateurWfs();
$nomMethode = 'formater'.$this->parametresRecherche->operation;
$parametre = isset($this->parametresRecherche->sources)
? $this->parametresRecherche->sources : null;
$retour = new ResultatService();
$retour->mime = self::MIME_WFS;
$retour->corps = $formateurWfs->$nomMethode($parametre);
}
} catch (Exception $erreur) {
$formateurWfs = new FormateurWfs();
$retour = new ResultatService();
$retour->mime = self::MIME_WFS;
$retour->corps = $formateurWfs->formaterException($erreur);
}
return $retour;
}
private function getFeature() {
if (array_key_exists('bbox', $this->parametres)) {
$this->traiterParametreBbox();
} elseif (array_key_exists('filter', $this->parametres)) {
$this->traiterParametreFilter();
}
$this->recupererStationsWfs();
$formateurWfs = new FormateurWfs();
$retour = new ResultatService();
$retour->mime = self::MIME_WFS;
$retour->corps = $formateurWfs->formaterGetFeature($this->retour, $this->parametresRecherche->sources);
return $retour;
}
private function traiterParametreOperation() {
if ($this->verifierExistenceParametre('request')) {
if (!$this->estOperationWfsAutorisee()) {
$message = "L'opération '".$this->parametres['request']."' n'est pas autorisée.\n".
"Les opérations suivantes sont permises par le service : ".Config::get('operations_wfs');
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
} else {
$this->parametresRecherche->operation = $this->parametres['request'];
}
}
}
private function verifierExistenceParametre($nomParametre) {
$estParametreExistant = false;
if (!array_key_exists($nomParametre, $this->parametres)) {
$message = "Le paramètre nom de l'opération '{$nomParametre}' ".
"n'a pas été trouvé dans la liste des paramètres.";
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
} else {
$estParametreExistant = true;
}
return $estParametreExistant;
}
private function estOperationWfsAutorisee() {
$operationsWfsService = explode(',' , Config::get('operations_wfs'));
return (in_array($this->parametres['request'], $operationsWfsService));
}
private function traiterParametreSource() {
// le parametre source (typename) est optionnel par defaut
if (array_key_exists('typename', $this->parametres)) {
$sources = explode(',', $this->parametres['typename']);
$estSourceValide = true;
foreach ($sources as $source) {
if (!$this->verifierExistenceSourcesDonnees($source)) {
$message = "Source de donnees '{$source}' indisponible. Les sources disponibles sont : ".
Config::get('sources_dispo');
$estSourceValide = false;
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
}
}
if ($estSourceValide) {
$this->parametresRecherche->sources = $sources;
}
}
}
private function traiterParametreBbox() {
$bboxVerifiee = $this->verifierCoordonneesBbox($this->parametres['bbox']);
if (is_array($bboxVerifiee) && count($bboxVerifiee) == 4) {
$this->parametresRecherche->bbox = array($bboxVerifiee);
}
}
private function verifierCoordonneesBbox($bbox) {
$bboxVerifiee = null;
// verifier que la chaine de caracteres $bbox est une serie de chaque nombre decimaux
// separes entre eux par une virgule
if (preg_match('/^(-?\d{1,3}(.\d+)?,){3}(-?\d{1,3}(.\d+)?)$/', $bbox) == 0) {
$message = "Format de saisie des coordonnees de la bounding box non valide. Le service ".
"n'accepte seulement qu'une serie de 4 nombre décimaux séparés par des virgules.";
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
} else {
$coordonnees = explode(',', $bbox);
$nomsIndexBbox = array("ouest", "sud", "est", "nord");
$bbox = array();
for ($i = 0; $i < count($coordonnees); $i ++) {
$bbox[$nomsIndexBbox[$i]] = $coordonnees[$i];
}
// verifier que les coordonnees de chaque bord de la bbox sont valides
if ($this->estUneBboxValide($bbox)) {
$bboxVerifiee = $bbox;
} else {
$message = "Certaines coordonnées de la bounding box sont situés en dehors des limites ".
"de notre monde";
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
}
}
return $bboxVerifiee;
}
private function estUneBboxValide($bbox) {
$monde = array(
'ouest' => floatval(Config::get('carte.limite_ouest')),
'est' => floatval(Config::get('carte.limite_est')),
'sud' => floatval(Config::get('carte.limite_sud')),
'nord' => floatval(Config::get('carte.limite_nord'))
);
return (floatval($bbox['ouest']) >= $monde['ouest'] && floatval($bbox['ouest']) <= $monde['est']
&& floatval($bbox['est']) >= $monde['ouest'] && floatval($bbox['est']) <= $monde['est']
&& floatval($bbox['nord']) >= $monde['sud'] && floatval($bbox['nord']) <= $monde['nord']
&& floatval($bbox['sud']) >= $monde['sud'] && floatval($bbox['sud']) <= $monde['nord']);
}
private function traiterParametreFilter() {
// la valeur du parametre filter est une chaine de texte qui compose en realite un document XML
// plus d'infos a l'URL suivante : http://mapserver.org/fr/ogc/filter_encoding.html
$filtreTexte = $this->recupererTexteParametreFilter();
$documentXML = new DomDocument();
$documentXML->loadXML($filtreTexte);
$filtres = $documentXML->documentElement->childNodes;
for ($index = 0; $index < $filtres->length; $index ++) {
$this->verifierFiltre($filtres->item($index));
}
}
private function recupererTexteParametreFilter() {
$parametresUrl = explode("&", $_SERVER['QUERY_STRING']);
$filtreTexte = '';
foreach ($parametresUrl as $parametre) {
list($cle, $valeur) = explode("=", $parametre);
if ($cle == 'filter') {
$filtreTexte = rawurldecode($valeur);
}
}
return $filtreTexte;
}
private function verifierFiltre($filtre) {
$operateursAcceptes = explode(',', Config::get('operateurs_wfs'));
$nomOperateur = $filtre->tagName;
if (!in_array($nomOperateur, $operateursAcceptes)) {
$message = "Le filtre '$nomOperateur' n'est pas pris en compte par le serrvice. ".
"Les opérateurs acceptés sont :".implode(', ', $operateursAcceptes);
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
} else {
if ($nomOperateur == 'BBOX') {
$bboxUrl = $filtre->lastChild->nodeValue;
$bboxVerifiee = $this->verifierCoordonneesBbox($bboxUrl);
$this->parametresRecherche->bbox = array($bboxVerifiee);
} else {
$this->traiterOperateurScalaire($filtre);
}
}
}
private function traiterOperateurScalaire($filtre) {
$nomOperateur = $filtre->tagName;
$champ = $filtre->childNodes->item(0)->nodeValue;
if ($champ != Config::get('champ_filtrage_wfs')) {
$message = "Le filtre ne peut pas être appliqué sur le champ '$champ'. ".
"Il est seulement accepté sur le champ '".Config::get('champ_filtrage_wfs')."'";
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
} else {
$valeur = $filtre->childNodes->item(1)->nodeValue;
$operateur = $nomOperateur == 'PropertyIsEqualTo' ? "=" : "LIKE";
$this->parametresRecherche->filtre = array("champ" => $champ, "operateur" => $operateur,
"valeur" => $valeur);
}
}
private function recupererStationsWfs() {
$this->nomMethode = $this->ressources[0];
foreach ($this->parametresRecherche->sources as $source) {
$source = trim($source);
$resultat = $this->traiterSource($source);
$this->ajouterResultat($resultat, $source);
}
}
/*********************************************/
// Verification parametres URL non-WFS
private function traiterRequeteNavigateur() {
$retour = null;
try {
if (!$this->estParametreSourceExistant()) {
$message = "Le paramètre source de données n'a pas été indiqué.";
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
} else {
$this->verifierParametres();
$listeSources = explode(',', $this->parametres['source']);
foreach ($listeSources as $source) {
$source = trim($source);
$resultat = $this->traiterSource($source);
$this->ajouterResultat($resultat, $source);
}
}
$formateur = new FormateurJson();
$nomMethode = 'formater'.ucfirst($this->ressources[0]);
$retour = new ResultatService();
$retour->corps = $formateur->$nomMethode($this->retour);
} catch (Exception $erreur) {
$retour = $erreur;
}
return $retour;
}
private function recupererRessourcesEtParametres($ressources, $parametres) {
$this->ressources = $ressources;
$this->parametres = array();
foreach ($parametres as $nomParametre => $valeur) {
$this->parametres[strtolower($nomParametre)] = $valeur;
}
}
private function estParametreSourceExistant() {
$parametreExiste = false;
if (isset($this->parametres['source'])) {
$parametreExiste = true;
}
return $parametreExiste;
}
private function verifierExistenceSourcesDonnees($source) {
$sourcesDisponibles = explode(',', Config::get('sources_dispo'));
$estDisponible = false;
if (in_array($source, $sourcesDisponibles)) {
$estDisponible = true;
}
return $estDisponible;
}
private function verifierParametres() {
$this->verificateur = new VerificateurParametres($this->parametres);
$this->verificateur->verifierParametres();
if ($this->verificateur->contientErreurs()) {
$this->verificateur->leverException();
} else {
$this->recupererParametresRecherche();
}
}
private function traiterSource($source) {
$retour = array();
if (!$this->verifierExistenceSourcesDonnees($source)) {
$message = "Source de donnees indisponible";
throw new Exception($message, RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
} else {
$this->chargerNomService($source);
$retour = $this->executerServicePourSource($source);
}
return $retour;
}
private function recupererParametresRecherche() {
$this->parametresRecherche = $this->verificateur->renvoyerResultatVerification();
}
private function chargerNomSource($source) {
if (isset($this->parametres['source'])) {
$this->nomSource = $this->parametres['source'];
} else {
$this->nomSource = Config::get('source_defaut');
}
}
private function chargerNomService($source) {
$this->nomService = ($source == 'floradata' ? 'Floradata' : 'Moissonnage').'Formateur';
Projets::chargerConfigurationSource($source);
}
private function executerServicePourSource($source) {
$objetTraitement = new $this->nomService($this->parametresRecherche, $source);
$methode = $this->genererNomMethodeAExecuter();
return $objetTraitement->$methode();
}
private function genererNomMethodeAExecuter() {
return 'recuperer' . ucfirst($this->ressources[0]);
}
private function ajouterResultat(& $resultat, $source) {
if (count($this->retour) > 0) {
if ($this->ressources[0] == 'stations' && count($resultat) > 0
&& $this->doitTransformerTypeDonnees($resultat)) {
$this->combinerResultats($resultat, $source);
} else {
$this->retour = array_merge($this->retour, $resultat);
}
} else {
$this->retour = array_merge($this->retour, $resultat);
}
}
private function doitTransformerTypeDonnees(& $resultat) {
return ($this->parametresRecherche->zoom <= Config::get('zoom_maximal_maillage') &&
(($resultat[0]['type_site'] == 'MAILLE' || $this->retour[0]['type_site'] == 'MAILLE')
|| ($resultat[0]['type_site'] != 'MAILLE' && $this->retour[0]['type_site'] != 'MAILLE'
&& count($resultat) + count($this->retour) > Config::get('seuil_maillage')))
);
}
private function combinerResultats(& $resultat, $source) {
$maillage = new Maillage($this->parametresRecherche->bbox, $this->parametresRecherche->zoom, $source);
$maillage->genererMaillesVides();
if ($resultat[0]['type_site'] == 'MAILLE') {
$maillage->ajouterMailles($resultat);
} else {
$maillage->ajouterStations($resultat);
}
if ($this->retour[0]['type_site'] == 'MAILLE') {
$maillage->ajouterMailles($this->retour);
} else {
$maillage->ajouterStations($this->retour);
}
$this->retour = $maillage->formaterSortie();
}
 
}
 
?>
/trunk/services/modules/0.1/sources/FloradataFormateur.php
New file
0,0 → 1,289
<?php
 
/**
*
* Classe en charge de recuperer les donnees d'observation ou liees a leur localisation
* Le jeu de donnees a interroger est celui utilise par l'application Carnet En Ligne
* (http://www.tela-botanica.org/page:cel)
*
* On passera en parametre lors de la creation d'une instance un objet contenant la liste des criteres
* qui vont restreindre le nombre de resultats a renvoyer
*
* Les deux operations suivantes peuvent etre utilisees dans les services :
* - recupererStations : va rechercher dans la base de donnees tous les points d'observations
* correspondant aux criteres de recherche demandes. La precision des lieux d'observation est
* soit un point precis, soit ramenee au niveau de la commune dans laquelle l'observation a ete faite
* En fonction du niveau de zoom et du nombre de resultats trouves, la presentation se fera
* soit par les points localisant les stations pour des niveaux de zoom eleves ou pour un nombre
* de stations inferieur a un seuil, ou par des mailles de 64*64 pixels dans le cas contraire
*
* - recupererObservations : va rechercher dans la base de donnees les donnees sur des observations
* a partir des coordonnees longitude et latitude d'une station (+ des parametres additionnels)
*
* Les donnees seront renvoyees au format JSON
*
* @package framework-0.4
* @author Alexandre GALIBERT <alexandre.galibert@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 2013 Tela Botanica (accueil@tela-botanica.org)
*
*/
 
 
final class FloradataFormateur extends Formateur {
final protected function construireRequeteStations() {
$condition = "(longitude IS NULL OR latitude IS NULL OR (longitude=0 AND latitude=0) ".
"OR longitude>180 OR latitude>90 OR mots_cles_texte LIKE '%sensible%')";
$requete =
"SELECT COUNT(id_observation) AS observations, ce_zone_geo, zone_geo, station, ".
"IF({$condition}, wgs84_latitude, latitude) AS latitude, IF({$condition}, wgs84_longitude, longitude) ".
"AS longitude, IF({$condition}, 'COMMUNE', 'STATION') AS type_site, 'floradata' AS source ".
"FROM cel_obs LEFT JOIN cel_zones_geo cz ON ce_zone_geo=id_zone_geo ".
"WHERE transmission=1 ".
$this->construireWhereDepartement().' '.
$this->construireWhereAuteur().' '.
$this->construireWhereDate().' '.
$this->construireWhereReferentiel().' '.
$this->construireWhereTaxon().' '.
$this->construireWhereCoordonneesBbox().' '.
"GROUP BY IF({$condition},wgs84_longitude,longitude), IF({$condition},wgs84_latitude,latitude)";
return $requete;
}
final protected function construireRequeteObservations() {
$requete =
"SELECT id_observation AS id_obs, nom_sel_nn AS nn, nom_referentiel, lieudit, milieu, ".
"(DATE(IF(date_observation != '0000-00-00 00:00:00', date_observation, date_transmission))) AS date, ".
"CONCAT(prenom_utilisateur, ' ', nom_utilisateur) AS observateur, ce_utilisateur AS observateurId, ".
"IF(nom_sel IS NULL, 'A identifier',nom_sel) AS nomSci, 'floradata' AS projet ".
"FROM cel_obs WHERE transmission=1 ".
$this->construireWhereAuteur().' '.
$this->construireWhereReferentiel().' '.
$this->construireWhereDate().' '.
$this->construireWhereTaxon().' '.
$this->construireWhereCoordonneesPoint().' '.
"ORDER BY IF(nom_sel IS NULL, 'A identifier',nom_sel), date, observateur";
return $requete;
}
final protected function construireRequeteWfs() {
$condition = "(longitude IS NULL OR latitude IS NULL OR (longitude=0 AND latitude=0) ".
"OR longitude>180 OR latitude>90 OR mots_cles_texte LIKE '%sensible%')";
$requete =
"SELECT nom_sel AS taxon, ce_zone_geo, zone_geo, station, 'floradata' AS source, ".
"IF({$condition}, wgs84_latitude, latitude) AS latitude, IF({$condition}, wgs84_longitude, longitude) ".
"AS longitude, IF({$condition}, 'commune', 'station') AS type_site, ".
"CONCAT(prenom_utilisateur, ' ', nom_utilisateur) AS auteur ".
"FROM cel_obs LEFT JOIN cel_zones_geo cz ON ce_zone_geo=id_zone_geo ".
"WHERE transmission=1 ".
$this->construireWhereCoordonneesBbox().' '.
$this->construireWhereNomScientifique().' '.
"ORDER BY IF({$condition},wgs84_longitude,longitude), IF({$condition},wgs84_latitude,latitude)";
return $requete;
}
private function construireWhereTaxon() {
$sql = '';
if (isset($this->criteresRecherche->taxon)) {
$taxons = $this->criteresRecherche->taxon;
$criteres = array();
foreach ($taxons as $taxon) {
if ($taxon['rang'] == Config::get('rang.famille')) {
$criteres[] = "famille=".$this->getBdd()->proteger($taxon['nom']);
} elseif ($taxon['rang'] == Config::get('rang.genre')) {
$criteres[] = "nom_sel LIKE ".$this->getBdd()->proteger($taxon['nom']." %");
} else {
$sousTaxons = $this->concatenerSynonymesEtSousEspeces($taxon);
$criteres[] = "nt IN (".implode(',', $sousTaxons).")";
}
}
$sql = "AND (".implode(' OR ',array_unique($criteres)).")";
}
return $sql;
}
 
private function concatenerSynonymesEtSousEspeces($taxon) {
$referentiel = new Referentiel($this->criteresRecherche->referentiel, $taxon);
$sousTaxons = $referentiel->recupererSynonymesEtSousEspeces();
$criteres = array();
foreach ($sousTaxons as $sousTaxon) {
$criteres[] = $sousTaxon['nt'];
}
return array_unique($criteres);
}
private function construireWhereReferentiel() {
$sql = '';
if (isset($this->criteresRecherche->referentiel) && !isset($this->criteresRecherche->taxon)) {
$referentiel = current(explode('_', $this->criteresRecherche->referentiel));
$sql = "AND nom_referentiel LIKE ".$this->getBdd()->proteger($referentiel."%");
}
return $sql;
}
private function construireWhereDepartement() {
$sql = '';
if (isset($this->criteresRecherche->departement)) {
$valeurs_a_proteger = $this->criteresRecherche->departement;
foreach ($valeurs_a_proteger as $valeur) {
$valeurs_protegees[] = "ce_zone_geo LIKE " . $this->getBdd()->proteger('INSEE-C:' . $valeur . '%');
}
$valeurs = implode(' OR ', $valeurs_protegees);
$sql = "AND ($valeurs)";
}
return $sql;
}
private function construireWhereAuteur() {
$sql = '';
if (isset($this->criteresRecherche->auteur)) {
$utilisateur = $this->getBdd()->proteger($this->criteresRecherche->auteur);
$sql = "AND courriel_utilisateur = $utilisateur";
}
return $sql;
}
private function construireWhereDate() {
$sql = '';
if (isset($this->criteresRecherche->nbJours)) {
$nbJours = $this->criteresRecherche->nbJours;
$sql = "AND (Datediff(Curdate(), date_transmission)<={$nbJours})";
} else {
$sql = $this->construireWhereDateDebutEtFin();
}
return $sql;
}
private function construireWhereDateDebutEtFin() {
$sql = '';
$dateDebut = isset($this->criteresRecherche->dateDebut) ? $this->criteresRecherche->dateDebut : null;
$dateFin = isset($this->criteresRecherche->dateFin) ? $this->criteresRecherche->dateFin : null;
if (!is_null($dateDebut) || !is_null($dateFin)) {
$dateFin = !is_null($dateFin) ? $dateFin : date('Y-m-d');
$condition = '';
if ($dateDebut == $dateFin) {
$condition = "DATE(date_observation)=".$this->getBdd()->proteger($dateDebut);
} elseif (is_null($dateFin)) {
$condition = "DATE(date_observation)>=".$this->getBdd()->proteger($dateDebut);
} elseif (is_null($dateDebut)) {
$condition = "DATE(date_observation)<=".$this->getBdd()->proteger($dateFin);
} else {
$condition = "DATE(date_observation) BETWEEN ".$this->getBdd()->proteger($dateDebut)." ".
"AND ".$this->getBdd()->proteger($dateFin);
}
$sql = "AND ($condition)";
}
return $sql;
}
private function construireWhereCoordonneesBbox() {
$sql = '';
if (isset($this->criteresRecherche->bbox)) {
$sql = "AND (".
"(".$this->genererCritereWhereBbox('').") OR (".
"(longitude IS NULL OR latitude IS NULL OR (longitude=0 AND latitude=0) ".
"OR longitude>180 OR latitude>90 OR mots_cles_texte LIKE '%sensible%') AND ".
$this->genererCritereWhereBbox('wgs84_').
")".
")";
}
return $sql;
}
private function genererCritereWhereBbox($suffixe) {
$bboxRecherche = $this->criteresRecherche->bbox;
$conditions = array();
$sql = '';
foreach ($bboxRecherche as $bbox) {
$conditions[] = "({$suffixe}latitude BETWEEN ".$bbox['sud']." AND ".$bbox['nord']." ".
"AND {$suffixe}longitude BETWEEN ".$bbox['ouest']." AND ".$bbox['est'].")";
}
if (count($conditions) > 0) {
$sql = '('.implode(' OR ', $conditions).')';
}
return $sql;
}
private function construireWhereNomScientifique() {
$sql = '';
if (isset($this->criteresRecherche->filtre)) {
$filtre = $this->criteresRecherche->filtre;
$valeur = "'{$filtre['valeur']}".($filtre['operateur'] == 'LIKE' ? "%" : "")."'";
switch ($filtre['champ']) {
case "taxon" : $sql = "AND nom_sel {$filtre['operateur']} {$valeur}"; break;
}
}
return $sql;
}
private function construireWhereCoordonneesPoint() {
$sql = '';
$conditions = array();
foreach ($this->criteresRecherche->stations as $station) {
if ($station[0] == $this->nomSource) {
$longitude = str_replace(",", ".", strval($station[3]));
$latitude = str_replace(",", ".", strval($station[2]));
if ($station[1] == 'station') {
$conditions[] = "(longitude=".$longitude." AND latitude=".$latitude." ".
"AND (mots_cles_texte IS NULL OR mots_cles_texte NOT LIKE '%sensible%'))";
} else {
$commune = $this->obtenirCoordonneesCommune($longitude, $latitude);
$conditions[] =
"(".
"((longitude IS NULL OR latitude IS NULL) OR (longitude=0 AND latitude=0) ".
"OR longitude>180 OR latitude>90 OR mots_cles_texte LIKE '%sensible%') ".
"AND ce_zone_geo=".$this->getBdd()->proteger($commune['id_zone_geo']).
")";
}
}
}
if (count($conditions) > 0) {
$sql = "AND (".implode(" OR ", $conditions).")";
}
return $sql;
}
private function obtenirCoordonneesCommune($longitude, $latitude) {
$requete = "SELECT id_zone_geo, nom FROM cel_zones_geo WHERE wgs84_longitude=$longitude ".
"AND wgs84_latitude=$latitude";
$commune = $this->getBdd()->recuperer($requete);
if ($commune === false) {
$commune = null;
}
return $commune;
}
final protected function obtenirNomsStationsSurPoint() {
// verifier si les coordonnees du point de requetage correspondent a une commune
$coordonnees = $this->recupererCoordonneesPremiereStation();
$station = $this->obtenirCoordonneesCommune($coordonnees[0], $coordonnees[1]);
if (is_null($station)) {
$requete = 'SELECT DISTINCT lieudit AS nom FROM cel_obs WHERE longitude='.
$coordonnees[0].' AND latitude='.$coordonnees[1];
$station = $this->getBdd()->recuperer($requete);
}
$nomStation = '';
if ($station !== false) {
$nomStation = trim($station['nom']);
}
return $nomStation;
}
private function recupererCoordonneesPremiereStation() {
$coordonnees = null;
foreach ($this->criteresRecherche->stations as $station) {
if ($station[0] == $this->nomSource) {
$longitude = str_replace(",", ".", strval($station[3]));
$latitude = str_replace(",", ".", strval($station[2]));
$coordonnees = array($longitude, $latitude);
}
}
return $coordonnees;
}
}
 
?>
/trunk/services/modules/0.1/sources/Formateur.php
New file
0,0 → 1,131
<?php
 
abstract class Formateur {
protected $criteresRecherche;
protected $bdd = null;
protected $nomSource = '';
public function __construct($criteresRecherche, $source) {
$this->criteresRecherche = $criteresRecherche;
$this->nomSource = $source;
}
protected function getBdd() {
if (is_null($this->bdd)) {
$this->bdd = new Bdd();
$nomBdd = $this->nomSource == 'floradata' ? Config::get('bdd_nom_floradata') : Config::get('bdd_nom_eflore');
$this->bdd->requeter("USE {$nomBdd}");
}
return $this->bdd;
}
public function recupererStations() {
$stations = array();
if ($this->nomSource == 'floradata' || $this->calculerNombreCriteresNonSpatiaux() > 0) {
$requeteSql = $this->construireRequeteStations();
$stations = $this->getBdd()->recupererTous($requeteSql);
if ($this->determinerFormatRetour(count($stations)) == 'maille') {
$maillage = new Maillage($this->criteresRecherche->bbox,
$this->criteresRecherche->zoom, $this->nomSource);
$maillage->genererMaillesVides();
$maillage->ajouterStations($stations);
$stations = $maillage->formaterSortie();
}
} else {
$nombreStations = $this->obtenirNombreStationsDansBbox();
if ($this->determinerFormatRetour($nombreStations) == 'maille') {
$stations = $this->recupererMaillesDansBbox();
} else {
$requeteSql = $this->construireRequeteStations();
$stations = $this->getBdd()->recupererTous($requeteSql);
}
}
return $stations;
}
public function recupererWfs() {
$requeteSql = $this->construireRequeteWfs();
return $this->getBdd()->recupererTous($requeteSql);
}
protected function determinerFormatRetour($nombreStations) {
$formatRetour = 'point';
$zoomMaxMaillage = Config::get('zoom_maximal_maillage');
if (isset($this->criteresRecherche->format) && $this->criteresRecherche->format == 'maille'
&& $this->criteresRecherche->zoom <= $zoomMaxMaillage) {
$formatRetour = 'maille';
} else {
$seuilMaillage = Config::get('seuil_maillage');
if ($this->criteresRecherche->zoom <= $zoomMaxMaillage && $nombreStations > $seuilMaillage) {
$formatRetour = 'maille';
}
}
return $formatRetour;
}
protected function calculerNombreCriteresNonSpatiaux() {
$nombreParametresNonSpatiaux = 0;
$criteresAIgnorer = array('zoom', 'bbox', 'stations', 'referentiel', 'format');
foreach ($this->criteresRecherche as $nomCritere => $valeur) {
if (!in_array($nomCritere, $criteresAIgnorer)) {
$nombreParametresNonSpatiaux ++;
}
}
return $nombreParametresNonSpatiaux;
}
abstract protected function construireRequeteStations();
protected function obtenirNombreStationsDansBbox() {}
protected function recupererMaillesDansBbox() {}
public function recupererObservations() {
$requeteSql = $this->construireRequeteObservations();
$observations = $this->getBdd()->recupererTous($requeteSql);
if ($this->nomSource != 'floradata') {
$this->recupererNumeroNomenclaturauxTaxons($observations);
}
$nomStation = $this->obtenirNomsStationsSurPoint();
if (strlen($nomStation) == 0) {
$nomStation = 'station sans nom';
}
for ($index = 0; $index < count($observations); $index ++) {
$observations[$index]['nom_station'] = $nomStation;
}
return $observations;
}
abstract protected function construireRequeteObservations();
protected function recupererNumeroNomenclaturauxTaxons(& $observations) {
for ($index = 0; $index < count($observations); $index ++) {
if (strlen (trim($observations[$index]['nomSci'])) == 0) {
continue;
}
$numeroNomenclatural = isset($observations[$index]['nn']) ? $observations[$index]['nn'] : null;
$referentiels = Referentiel::recupererListeReferentielsDisponibles();
$taxon = null;
$indexRef = 0;
while ($indexRef < count($referentiels) && is_null($taxon)) {
$referentiel = new Referentiel($referentiels[$indexRef]);
$taxon = $referentiel->obtenirNumeroNomenclatural($observations[$index]['nomSci'],
$numeroNomenclatural);
$indexRef ++;
}
if (!is_null($taxon)) {
$observations[$index]['nn'] = $taxon['nn'];
$observations[$index]['nom_referentiel'] = $taxon['referentiel'];
} else {
$observations[$index]['nn'] = '';
}
}
}
abstract protected function obtenirNomsStationsSurPoint();
}
 
?>
/trunk/services/modules/0.1/sources/MoissonnageFormateur.php
New file
0,0 → 1,266
<?php
 
/**
*
* Classe en charge de recuperer les donnees d'observation ou liees a leur localisation
* Le jeu de donnees a interroger est partage en commun avec l'application EFlore
*
* On passera en parametre lors de la creation d'une instance un objet contenant la liste des criteres
* qui vont restreindre le nombre de resultats a renvoyer
*
* Les deux operations suivantes peuvent etre utilisees dans les services :
* - recupererStations : va rechercher dans la base de donnees tous les points d'observations
* correspondant aux criteres de recherche demandes. La precision des lieux d'observation est
* soit un point precis, soit ramenee au niveau de la commune dans laquelle l'observation a ete faite
* En fonction du niveau de zoom et du nombre de resultats trouves, la presentation se fera
* soit par les points localisant les stations pour des niveaux de zoom eleves ou pour un nombre
* de stations inferieur a un seuil, ou par des mailles de 64*64 pixels dans le cas contraire
*
* - recupererObservations : va rechercher dans la base de donnees les donnees sur des observations
* a partir des coordonnees longitude et latitude d'une station (+ des parametres additionnels)
*
* Les donnees seront renvoyees au format JSON
*
* @package framework-0.4
* @author Alexandre GALIBERT <alexandre.galibert@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 2013 Tela Botanica (accueil@tela-botanica.org)
*
*/
 
class MoissonnageFormateur extends Formateur {
 
final protected function construireRequeteStations() {
$requete =
"SELECT COUNT(guid) AS observations, lieu_station_nom AS nom, lieu_station_latitude AS latitude, ".
"lieu_station_longitude AS longitude, 'STATION' AS type_site, lieu_commune_code_insee AS code_insee, ".
"'{$this->nomSource}' AS source FROM {$this->nomSource}_tapir WHERE 1 ".
$this->construireWhereDepartement().' '.
$this->construireWhereAuteur().' '.
$this->construireWhereDate().' '.
$this->construireWhereReferentiel().' '.
$this->construireWhereTaxon().' '.
$this->construireWhereCoordonneesBbox().' '.
"GROUP BY lieu_station_longitude, lieu_station_latitude";
return $requete;
}
final protected function construireRequeteObservations() {
$requete =
"SELECT observation_id AS id_obs, nom_scientifique_complet AS nomSci, ".
"observation_date AS date, lieu_station_nom AS lieu, observateur_nom_complet AS observateur, ".
"'{$this->nomSource}' AS projet FROM {$this->nomSource}_tapir WHERE 1 ".
$this->construireWhereAuteur().' '.
$this->construireWhereReferentiel().' '.
$this->construireWhereDate().' '.
$this->construireWhereTaxon().' '.
$this->construireWhereCoordonneesPoint().' '.
"ORDER BY nom_scientifique_complet, date, observateur";
return $requete;
}
final protected function construireRequeteWfs() {
$requete =
"SELECT nom_scientifique_complet AS taxon, lieu_station_nom AS nom, lieu_station_latitude AS latitude, ".
"lieu_station_longitude AS longitude, 'station' AS type_site, lieu_commune_code_insee AS code_insee, ".
"'{$this->nomSource}' AS source, observateur_nom_complet AS auteur ".
"FROM {$this->nomSource}_tapir WHERE 1 ".
$this->construireWhereCoordonneesBbox().' '.
$this->construireWhereNomScientifique().' '.
"ORDER BY lieu_station_longitude, lieu_station_latitude";
return $requete;
}
private function construireWhereTaxon() {
$sql = '';
if (isset($this->criteresRecherche->taxon)) {
$taxons = $this->criteresRecherche->taxon;
$criteres = array();
foreach ($taxons as $taxon) {
$criteres[] = "nom_scientifique_complet LIKE ".$this->getBdd()->proteger($taxon['nom']."%");
if ($taxon['rang'] >= Config::get('rang.espece')) {
$criteres = array_merge($criteres, $this->concatenerSynonymesEtSousEspeces($taxon));
} elseif ($taxon['rang'] == Config::get('rang.famille')) {
$criteres = array_merge($criteres, $this->concatenerTaxonsGenres($taxon));
}
}
$sql = "AND (".implode(' OR ',array_unique($criteres)).")";
}
return $sql;
}
private function concatenerSynonymesEtSousEspeces($taxon) {
$referentiel = new Referentiel($this->criteresRecherche->referentiel, $taxon);
$sousTaxons = $referentiel->recupererSynonymesEtSousEspeces();
$criteres = array();
foreach ($sousTaxons as $sousTaxon) {
$criteres[] = "nom_scientifique_complet LIKE ".$this->getBdd()->proteger($sousTaxon['nom']."%");
}
return $criteres;
}
private function concatenerTaxonsGenres($taxon) {
$referentiel = new Referentiel($this->criteresRecherche->referentiel, $taxon);
$sousTaxons = $referentiel->recupererGenres();
$criteres = array();
foreach ($sousTaxons as $sousTaxon) {
$criteres[] = "nom_scientifique_complet LIKE ".$this->getBdd()->proteger($sousTaxon['nom']."%");
}
return $criteres;
}
private function construireWhereReferentiel() {
$sql = '';
if (isset($this->criteresRecherche->referentiel)) {
$referentielSource = Config::get('referentiel_source');
if (strstr($this->criteresRecherche->referentiel, $referentielSource) === false) {
$sql = "AND 0";
}
}
return $sql;
}
private function construireWhereDepartement() {
$sql = '';
if (isset($this->criteresRecherche->departement)) {
$valeurs_a_proteger = $this->criteresRecherche->departement;
foreach ($valeurs_a_proteger as $valeur) {
$aProteger = $this->getBdd()->proteger($valeur . '%');
$valeurs_protegees[] = "lieu_commune_code_insee LIKE {$aProteger}";
}
$valeurs = implode(' OR ', $valeurs_protegees);
$sql = "AND ($valeurs)";
}
return $sql;
}
private function construireWhereAuteur() {
$sql = '';
if (isset($this->criteresRecherche->auteur)) {
$auteur = $this->getBdd()->proteger($this->criteresRecherche->auteur);
$sql = "AND observateur_nom_complet = $auteur";
}
return $sql;
}
 
private function construireWhereDate() {
$sql = '';
$dateDebut = isset($this->criteresRecherche->dateDebut) ? $this->criteresRecherche->dateDebut : null;
$dateFin = isset($this->criteresRecherche->dateFin) ? $this->criteresRecherche->dateFin : null;
if (!is_null($dateDebut) || !is_null($dateFin)) {
$dateDebut = !is_null($dateDebut) ? substr($dateDebut, 0, 4) : null;
$dateFin = !is_null($dateFin) ? substr($dateFin, 0, 4) : date('Y');
$condition = '';
if ($dateDebut == $dateFin) {
$condition = "observation_date=".$dateDebut;
} elseif (is_null($dateFin)) {
$condition = "observation_date>=".$dateDebut;
} elseif (is_null($dateDebut)) {
$condition = "observation_date<=".$dateFin;
} else {
$condition = "observation_date BETWEEN ".$dateDebut." AND ".$dateFin;
}
$sql = "AND ($condition)";
}
return $sql;
}
private function construireWhereCoordonneesBbox() {
$sql = '';
if (isset($this->criteresRecherche->bbox)) {
$bboxRecherche = $this->criteresRecherche->bbox;
$conditions = array();
foreach ($bboxRecherche as $bbox) {
$conditions[] = "(lieu_station_longitude BETWEEN ".$bbox['ouest']." AND ".$bbox['est']." ".
"AND lieu_station_latitude BETWEEN ".$bbox['sud']." AND ".$bbox['nord'].")";
}
$sql = 'AND ('.implode(' OR ', $conditions).')';
}
return $sql;
}
private function construireWhereNomScientifique() {
$sql = '';
if (isset($this->criteresRecherche->filtre)) {
$filtre = $this->criteresRecherche->filtre;
$valeur = "'{$filtre['valeur']}".($filtre['operateur'] == 'LIKE' ? "%" : "")."'";
switch ($filtre['champ']) {
case "taxon" : $sql = "AND nom_scientifique_complet {$filtre['operateur']} {$valeur}"; break;
}
}
return $sql;
}
private function construireWhereCoordonneesPoint() {
$sql = '';
$conditions = array();
foreach ($this->criteresRecherche->stations as $station) {
if ($station[0] == $this->nomSource) {
$longitude = str_replace(",", ".", strval($station[2]));
$latitude = str_replace(",", ".", strval($station[3]));
$conditions[] = "(lieu_station_latitude={$longitude} AND lieu_station_longitude={$latitude})";
}
}
if (count($conditions) > 0) {
$sql = "AND (".implode(" OR ", $conditions).")";
}
return $sql;
}
final protected function obtenirNomsStationsSurPoint() {
$requete = "SELECT DISTINCTROW lieu_station_nom FROM {$this->nomSource}_tapir WHERE 1 ".
$this->construireWhereTaxon().' '.
$this->construireWhereCoordonneesPoint();
$stations = $this->getBdd()->recupererTous($requete);
$nomsStations = array();
foreach ($stations as $station) {
$nomsStations[] = $station['lieu_station_nom'];
}
return implode(', ', $nomsStations);
}
final protected function obtenirNombreStationsDansBbox() {
$bbox = $this->criteresRecherche->bbox;
$zoom = $this->criteresRecherche->zoom;
$requete =
"SELECT zoom, Sum(nombre_sites) AS total_points FROM mailles_{$this->nomSource} ".
"WHERE zoom=".$zoom." ".$this->construireWhereMaillesBbox()." GROUP BY zoom";
$resultat = $this->getBdd()->recuperer($requete);
return $resultat['total_points'];
}
final protected function recupererMaillesDansBbox() {
$bbox = $this->criteresRecherche->bbox;
$zoom = $this->criteresRecherche->zoom;
$requete =
"SELECT limite_sud AS sud, limite_ouest AS ouest, limite_est AS est, limite_nord AS nord, ".
"nombre_sites AS stations, nombre_observations AS observations FROM mailles_{$this->nomSource} ".
"WHERE zoom=".$zoom." ".$this->construireWhereMaillesBbox();
$mailles = $this->getBdd()->recupererTous($requete);
// placer les totaux des nombres de stations dans des mailles vides
$maillage = new Maillage($this->criteresRecherche->bbox, $zoom, $this->nomSource);
$maillage->genererMaillesVides();
$maillage->ajouterMailles($mailles);
return $maillage->formaterSortie();
}
private function construireWhereMaillesBbox() {
$bboxRecherche = $this->criteresRecherche->bbox;
$conditions = array();
$sql = '';
foreach ($bboxRecherche as $bbox) {
$conditions[] = "(limite_sud<=".$bbox['nord']." AND limite_nord>=".$bbox['sud']." ".
"AND limite_ouest<=". $bbox['est']." AND limite_est>=".$bbox['ouest'].")";
}
if (count($conditions) > 0) {
$sql = 'AND ('.implode(' OR ', $conditions).')';
}
return $sql;
}
}
 
?>
/trunk/services/configurations/config_sophy.ini
New file
0,0 → 1,15
; Encodage : UTF-8
 
; Nom du projet
nom_source = "sophy"
 
; Nom de la base utilisée.
bdd_nom_eflore = "tb_eflore"
 
; URL de base des services de ce projet
url_service="{ref:url_base}service:moissonnage:0.1/sophy"
 
referentiel_source = "bdtfx"
 
[meta-donnees]
dureecache = 3600
/trunk/services/configurations/config.defaut.ini
New file
0,0 → 1,97
; Encodage : UTF-8
 
; +------------------------------------------------------------------------------------------------------+
; URLs
; Le séparateur utilisé par le framework lorsqu'il génère des URL pour séparer les arguments.
; Pour remettre les valeurs par défaut, utitliser : "php:ini_get('arg_separator.output')"
url_arg_separateur_sortie = "&"
 
; +------------------------------------------------------------------------------------------------------+
; Info sur l'application
info.nom = Services d'eFlore
; Abréviation de l'application
info.abr = carto-services
; Version du Framework nécessaire au fonctionnement de cette application
info.framework.version = 0.3
;Encodage de l'application
encodage_appli = "UTF-8"
 
; +------------------------------------------------------------------------------------------------------+
; Débogage
; Indique si oui ou non on veut afficher le débogage.
debogage = true
; Indique sous quelle forme les méssages de débogage doivent s'afficher :
; - "php:Debug::MODE_ECHO" : le message est affiché en utilisant echo
; - "php:Debug::MODE_NOTICE" : le message est affiché en utilisant une erreur de type notice
; - "php:Debug::MODE_ENTETE_HTTP" : les messages sont envoyés dans un entête HTTP "X_REST_DEBOGAGE".
; - "Autre valeur" : les messages sont formatés puis retournés par la méthode de débogage utilisée.
debogage_mode = "php:Debug::MODE_ECHO"
; Indique si oui ou non on veut lancer le chronométrage
chronometrage = false
 
 
; +------------------------------------------------------------------------------------------------------+
; Paramètrage de la base de données.
; Abstraction de la base de données.
bdd_abstraction = pdo
; Protocole de la base de données.
bdd_protocole = mysql
; Nom du serveur de bases de données.
bdd_serveur = localhost
; Nom de l'utilisateur de la base de données.
bdd_utilisateur = ""
; Mot de passe de l'utilisateur de la base de données.
bdd_mot_de_passe = ""
; Nom de la base de données principale.
bdd_nom = "tb_eflore"
; Encodage de la base de données principale au format base de données (ex. pour l'utf-8 ne pas mettre le tiret!).
bdd_encodage = "utf8"
 
; +------------------------------------------------------------------------------------------------------+
; Infos sur les services
;chemin direct aux services
serveur.baseURL = /moissonnage/services/
;URL à rediriger
serveur.baseAlternativeURL = /service:moissonnage:0.1/
 
; Version des service web du projet
service_version = 0.1
; Standard utilisé pour les codes de langue
langue_source = "ISO-639-1";
; Standard utilisé pour les codes de zones géographiques
zone_geo_source = "ISO-3166-1";
 
; URL de base des services
url_base="http://localhost/"
; URL de base des services
url_service_base='{ref:url_base}service:moissonnage:0.1/'
 
 
 
; +------------------------------------------------------------------------------------------------------+
; Infos sur les controles a effectuer sur les cartes et les donnees a afficher
carte.limite_ouest = -180
carte.limite_est = 180
carte.limite_sud = -85.051129
carte.limite_nord = 85.051129
carte.zoom_minimal = 3
carte.zoom_maximal = 18
zoom_maximal_maillage = 13
seuil_maillage = 250
 
; valeurs des rangs au niveau de la classification des taxons
rang.genre = 220
rang.famille = 180
rang.espece = 290
rang.sous_espece = 320
 
; +------------------------------------------------------------------------------------------------------+
; Autres informations
sources_dispo = "floradata,sophy,baznat"
source_defaut = "floradata"
services_dispo = "stations,observations,wfs"
referentiels_dispo = "bdtfx_v1_01,bdtxa_v1_00"
 
operations_wfs = "GetCapabilities,DescribeFeatureType,GetFeature"
operateurs_wfs = "PropertyIsEqualTo,PropertyIsLike,BBOX"
champ_filtrage_wfs = "taxon"
/trunk/services/configurations/config_floradata.ini
New file
0,0 → 1,15
; Encodage : UTF-8
 
; Nom du projet
nom_source = "floradata"
 
; Nom de la base utilisée.
bdd_nom_floradata = "tb_cel"
bdd_nom_eflore = "tb_eflore"
 
; URL de base des services de ce projet
url_service="{ref:url_base}service:moissonnage:0.1/floradata"
 
 
[meta-donnees]
dureecache = 3600
/trunk/services/configurations/config_baznat.ini
New file
0,0 → 1,16
; Encodage : UTF-8
 
; Nom du projet
nom_source = "baznat"
 
; Nom de la base utilisée.
bdd_nom_eflore = "tb_eflore"
 
; URL de base des services de ce projet
url_service="{ref:url_base}service:moissonnage:0.1/baznat"
 
referentiel_source = "bdtfx"
 
 
[meta-donnees]
dureecache = 3600
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/services/configurations
New file
Property changes:
Added: svn:ignore
+config.ini
/trunk/services/framework.defaut.php
New file
0,0 → 1,6
<?php
// Inclusion du Framework
// Renomer ce fichier en "framework.php"
// Indiquer ci-dessous le chemin absolu vers le fichier autoload.inc.php de la bonne version du Framework
require_once '/home/alex/web/framework-0.3/framework/Framework.php';
?>
/trunk/services/bibliotheque/CacheMoissonnage.php
New file
0,0 → 1,70
<?php
class CacheMoissonnage {
private $service;
private $config;
private $dureecache = 0;
private $serviceNom;
private $cache;
private $cacheActif;
public function __construct($service, $serviceNom, $cacheActif) {
$this->cacheActif = $cacheActif;
$this->service = $service;
$this->chargerDureeCache();
$this->serviceNom = $serviceNom;
$this->cache = new CacheSimple(array(
"mise_en_cache" => true,
"stockage_chemin" => Config::get("chemincache"),
"duree_de_vie" => $this->dureecache
));
}
 
public function chargerDureeCache() {
if ($this->cacheActif == "1") {
$this->dureecache = $this->service->getDureeCache();
}
}
public function consulter($ressources, $parametres) {
$id = $this->genererID($ressources, $parametres);
$retour = unserialize($this->cache->charger($id));
if ($retour == false) {
$retour = $this->mettreEnCache($ressources, $parametres);
}
return $retour;
}
public function mettreEnCache($ressources, $parametres) {
$retour = $this->service->consulter($ressources, $parametres);
$id = $this->genererID($ressources, $parametres);
if ($this->dureecache > 0) {
$this->cache->sauver(serialize($retour), $id);
}
return $retour;
}
public function genererID($ressources, $parametres) {
$chaineRessources = "";
$chaineParametres = "";
if (count($ressources) > 0) {
foreach ($ressources as $key => $val) {
$chaineRessources .= "$key:$val;";
}
}
if (count($parametres) > 0) {
foreach ($parametres as $key => $val) {
$chaineParametres .= "$key:$val;";
}
}
$chaineMD5 = $this->serviceNom.'/'.md5($chaineRessources.$chaineParametres);
return $chaineMD5;
}
}
 
 
?>
/trunk/services/bibliotheque/squelettes/GetCapabilities.tpl.xml
New file
0,0 → 1,153
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'."\n"; ?>
<wfs:WFS_Capabilities
xmlns:gml="http://www.opengis.net/gml"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ows="http://www.opengis.net/ows"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns="http://www.opengis.net/wfs"
version="1.1.0"
xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<ows:ServiceIdentification>
<ows:Title>Observations Tela-Botanica</ows:Title>
<ows:Abstract>Observations Tela-Botanica</ows:Abstract>
<ows:Keywords>
<ows:Keyword>Tela-Botanica</ows:Keyword>
<ows:Keyword>Botanique</ows:Keyword>
<ows:Keyword>Observation naturaliste</ows:Keyword>
</ows:Keywords>
<ows:ServiceType codeSpace="OGC">OGC WFS</ows:ServiceType>
<ows:ServiceTypeVersion>1.1.0</ows:ServiceTypeVersion>
<ows:Fees>none</ows:Fees>
<ows:AccessConstraints>none</ows:AccessConstraints>
</ows:ServiceIdentification>
<ows:ServiceProvider>
<ows:ProviderName>Association Tela-Botanica</ows:ProviderName>
<ows:ProviderSite xlink:type="simple" xlink:href="http://tela-botanica.org" />
<ows:ServiceContact>
<ows:IndividualName>Tela-Botanica</ows:IndividualName>
<ows:ContactInfo>
<ows:Phone>
<ows:Voice>+33 467524122</ows:Voice>
</ows:Phone>
<ows:Address>
<ows:DeliveryPoint>4, Rue de Belfort</ows:DeliveryPoint>
<ows:City>Montpellier</ows:City>
<ows:AdministrativeArea>Hérault (34)</ows:AdministrativeArea>
<ows:PostalCode>34000</ows:PostalCode>
<ows:Country>France</ows:Country>
<ows:ElectronicMailAddress>accueil@tela-botanica.org</ows:ElectronicMailAddress>
</ows:Address>
<ows:Role>resourceProvider</ows:Role>
</ows:ContactInfo>
</ows:ServiceContact>
</ows:ServiceProvider>
<ows:OperationsMetadata>
<ows:Operation name="GetCapabilities">
<ows:DCP>
<ows:HTTP>
<ows:Get xlink:type="simple" xlink:href="<?php echo Config::get('url_service_base'); ?>wfs" />
<ows:Post xlink:type="simple" xlink:href="<?php echo Config::get('url_service_base'); ?>wfs" />
</ows:HTTP>
</ows:DCP>
<ows:Parameter name="service">
<ows:Value>WFS</ows:Value>
</ows:Parameter>
<ows:Parameter name="AcceptVersions">
<ows:Value>1.1.0</ows:Value>
</ows:Parameter>
<ows:Parameter name="AcceptFormat">
<ows:Value>text/xml</ows:Value>
</ows:Parameter>
</ows:Operation>
<ows:Operation name="DescribeFeatureType">
<ows:DCP>
<ows:HTTP>
<ows:Get xlink:type="simple" xlink:href="<?php echo Config::get('url_service_base'); ?>wfs" />
<ows:Post xlink:type="simple" xlink:href="<?php echo Config::get('url_service_base'); ?>wfs" />
</ows:HTTP>
</ows:DCP>
<ows:Parameter name="outputFormat">
<ows:Value>text/xml; subtype=gml/3.1.1</ows:Value>
</ows:Parameter>
</ows:Operation>
<ows:Operation name="GetFeature">
<ows:DCP>
<ows:HTTP>
<ows:Get xlink:type="simple" xlink:href="<?php echo Config::get('url_service_base'); ?>wfs" />
<ows:Post xlink:type="simple" xlink:href="<?php echo Config::get('url_service_base'); ?>wfs" />
</ows:HTTP>
</ows:DCP>
<ows:Parameter name="resultType">
<ows:Value>results</ows:Value>
</ows:Parameter>
<ows:Parameter name="outputFormat">
<ows:Value>text/xml; subtype=gml/3.1.1</ows:Value>
</ows:Parameter>
</ows:Operation>
</ows:OperationsMetadata>
<FeatureTypeList>
<Operations>
<Operation>Query</Operation>
</Operations>
<FeatureType>
<Name>floradata</Name>
<Title>FloraData</Title>
<Abstract>Base de données constituée d'observations publiques du Carnet en Ligne de Tela Botanica. URL : http://www.tela-botanica.org/appli:cel</Abstract>
<DefaultSRS>EPSG:4326</DefaultSRS>
<OutPutFormats>
<Format>text/xml; subtype=gml/3.1.1</Format>
</OutPutFormats>
<ows:WGS84BoundingBox dimensions="2">
<ows:LowerCorner>-180 -90</ows:LowerCorner>
<ows:UpperCorner>180 90</ows:UpperCorner>
</ows:WGS84BoundingBox>
</FeatureType>
<FeatureType>
<Name>sophy</Name>
<Title>SOPHY, banque de données botaniques et écologiques</Title>
<Abstract>Données issues de SOPHY, une banque de données botaniques et écologiques réalisée par P. DE RUFFRAY, H. BRISSE, G. GRANDJOUAN et E. GARBOLINO dans le cadre de l'Association d'Informatique Appliquée à la Botanique (A.I.A.B.). URL : http://sophy.u-3mrs.fr/</Abstract>
<DefaultSRS>EPSG:4326</DefaultSRS>
<OutPutFormats>
<Format>text/xml; subtype=gml/3.1.1</Format>
</OutPutFormats>
<ows:WGS84BoundingBox dimensions="2">
<ows:LowerCorner>-180 -90</ows:LowerCorner>
<ows:UpperCorner>180 90</ows:UpperCorner>
</ows:WGS84BoundingBox>
</FeatureType>
<FeatureType>
<Name>baznat</Name>
<Title>BazNat - Flore</Title>
<Abstract>Données issues des prospections flore de la base de données naturaliste du réseau BazNat. URL : http://www.baznat.net/</Abstract>
<DefaultSRS>EPSG:4326</DefaultSRS>
<OutPutFormats>
<Format>text/xml; subtype=gml/3.1.1</Format>
</OutPutFormats>
<ows:WGS84BoundingBox dimensions="2">
<ows:LowerCorner>-180 -90</ows:LowerCorner>
<ows:UpperCorner>180 90</ows:UpperCorner>
</ows:WGS84BoundingBox>
</FeatureType>
</FeatureTypeList>
<ogc:Filter_Capabilities>
<ogc:Spatial_Capabilities>
<ogc:SpatialOperators>
<ogc:SpatialOperator name="BBOX"/>
</ogc:SpatialOperators>
</ogc:Spatial_Capabilities>
<ogc:Scalar_Capabilities>
<ogc:ComparisonOperators>
<ogc:ComparisonOperator>EqualTo</ogc:ComparisonOperator>
<ogc:ComparisonOperator>NotEqualTo</ogc:ComparisonOperator>
<ogc:ComparisonOperator>Like</ogc:ComparisonOperator>
</ogc:ComparisonOperators>
</ogc:Scalar_Capabilities>
</ogc:Filter_Capabilities>
</wfs:WFS_Capabilities>
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/services/bibliotheque/squelettes/GetFeature.tpl.xml
New file
0,0 → 1,31
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'."\n"; ?>
<wfs:FeatureCollection
xmlns:ms="http://mapserver.gis.umn.edu/mapserver"
xmlns:gml="http://www.opengis.net/gml"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver <?php echo Config::get('url_service_base'); ?>wfs?service=wfs&amp;version=1.1.0&amp;request=DescribeFeatureType&amp;typename=<?php echo $listeSources; ?> http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<gml:boundedBy>
<gml:Box srsName="EPSG:4326">
<gml:coordinates decimal="." cs="," ts=" "><?=$enveloppe['ouest']?>,<?=$enveloppe['sud']?>,<?=$enveloppe['est']?>,<?=$enveloppe['nord']?></gml:coordinates>
</gml:Box>
</gml:boundedBy>
<?php foreach ($stations as $station) { ?>
<gml:featureMember>
<ms:<?=$station['source']?>>
<ms:coordonnees>
<gml:Point srsName="EPSG:4326">
<gml:coordinates decimal="." cs="," ts=" "><?=$station['longitude']?>,<?=$station['latitude']?></gml:coordinates>
</gml:Point>
</ms:coordonnees>
<ms:nomStation><?=$station['nom_station']?></ms:nomStation>
<ms:precision><?=$station['type_site']?></ms:precision>
<ms:codeInsee><?=$station['code_insee']?></ms:codeInsee>
<ms:departement><?=$station['departement']?></ms:departement>
<ms:taxons><?=$station['taxons']?></ms:taxons>
<ms:auteurs><?=$station['auteurs']?></ms:auteurs>
</ms:<?=$station['source']?>>
</gml:featureMember>
<?php } ?>
</wfs:FeatureCollection>
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/services/bibliotheque/squelettes/DescribeFeatureType.tpl.xml
New file
0,0 → 1,29
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'."\n"; ?>
<schema
targetNamespace="http://mapserver.gis.umn.edu/mapserver"
xmlns:ms="http://mapserver.gis.umn.edu/mapserver"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:gml="http://www.opengis.net/gml"
elementFormDefault="qualified" version="0.1" >
<import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/3.1.1/base/gml.xsd" />
<?php foreach ($listeSources as $source) { ?>
<element name="<?=$source ?>" type="ms:<?=$source ?>Type" substitutionGroup="gml:_Feature" />
<complexType name="<?=$source ?>Type">
<complexContent>
<extension base="gml:AbstractFeatureType">
<sequence>
<element name="coordonnees" type="gml:Point" />
<element name="nomStation" type="string" />
<element name="precision" type="string" />
<element name="codeInsee" type="string" />
<element name="departement" type="string" />
<element name="taxons" type="string" />
<element name="auteurs" type="string" />
</sequence>
</extension>
</complexContent>
</complexType>
<?php } ?>
</schema>
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/services/bibliotheque/squelettes/Exception.tpl.xml
New file
0,0 → 1,7
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'."\n"; ?>
<ows:ExceptionReport xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ows="http://www.opengis.net/ows/1.1" version="1.1.0" xml:lang="en-US" xsi:schemaLocation="http://www.opengis.net/ows/1.1 http://schemas.opengis.net/ows/1.1.0/owsExceptionReport.xsd">
xsi:schemaLocation="http://www.opengis.net/ows/1.1 http://schemas.opengis.net/ows/1.1.0/owsExceptionReport.xsd">
<ows:Exception exceptionCode="typename" locator="InvalidParameterValue">
<ows:ExceptionText><?=$message?></ows:ExceptionText>
</ows:Exception>
</ows:ExceptionReport>
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/services/bibliotheque/JSON.php
New file
0,0 → 1,806
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
* Converts to and from JSON format.
*
* JSON (JavaScript Object Notation) is a lightweight data-interchange
* format. It is easy for humans to read and write. It is easy for machines
* to parse and generate. It is based on a subset of the JavaScript
* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
* This feature can also be found in Python. JSON is a text format that is
* completely language independent but uses conventions that are familiar
* to programmers of the C-family of languages, including C, C++, C#, Java,
* JavaScript, Perl, TCL, and many others. These properties make JSON an
* ideal data-interchange language.
*
* This package provides a simple encoder and decoder for JSON notation. It
* is intended for use with client-side Javascript applications that make
* use of HTTPRequest to perform server communication functions - data can
* be encoded into JSON notation for use in a client-side javascript, or
* decoded from incoming Javascript requests. JSON format is native to
* Javascript, and can be directly eval()'ed with no further parsing
* overhead
*
* All strings should be in ASCII or UTF-8 format!
*
* LICENSE: Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met: Redistributions of source code must retain the
* above copyright notice, this list of conditions and the following
* disclaimer. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* @category
* @package Services_JSON
* @author Michal Migurski <mike-json@teczno.com>
* @author Matt Knapp <mdknapp[at]gmail[dot]com>
* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
* @copyright 2005 Michal Migurski
* @version CVS: $Id$
* @license http://www.opensource.org/licenses/bsd-license.php
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
*/
 
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_SLICE', 1);
 
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_STR', 2);
 
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_ARR', 3);
 
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_OBJ', 4);
 
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_CMT', 5);
 
/**
* Behavior switch for Services_JSON::decode()
*/
define('SERVICES_JSON_LOOSE_TYPE', 16);
 
/**
* Behavior switch for Services_JSON::decode()
*/
define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
 
/**
* Converts to and from JSON format.
*
* Brief example of use:
*
* <code>
* // create a new instance of Services_JSON
* $json = new Services_JSON();
*
* // convert a complexe value to JSON notation, and send it to the browser
* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
* $output = $json->encode($value);
*
* print($output);
* // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
*
* // accept incoming POST data, assumed to be in JSON notation
* $input = file_get_contents('php://input', 1000000);
* $value = $json->decode($input);
* </code>
*/
class Services_JSON
{
/**
* constructs a new JSON instance
*
* @param int $use object behavior flags; combine with boolean-OR
*
* possible values:
* - SERVICES_JSON_LOOSE_TYPE: loose typing.
* "{...}" syntax creates associative arrays
* instead of objects in decode().
* - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
* Values which can't be encoded (e.g. resources)
* appear as NULL instead of throwing errors.
* By default, a deeply-nested resource will
* bubble up with an error, so all return values
* from encode() should be checked with isError()
*/
function Services_JSON($use = 0)
{
$this->use = $use;
}
 
/**
* convert a string from one UTF-16 char to one UTF-8 char
*
* Normally should be handled by mb_convert_encoding, but
* provides a slower PHP-only method for installations
* that lack the multibye string extension.
*
* @param string $utf16 UTF-16 character
* @return string UTF-8 character
* @access private
*/
function utf162utf8($utf16)
{
// oh please oh please oh please oh please oh please
if(function_exists('mb_convert_encoding')) {
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
}
 
$bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
 
switch(true) {
case ((0x7F & $bytes) == $bytes):
// this case should never be reached, because we are in ASCII range
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0x7F & $bytes);
 
case (0x07FF & $bytes) == $bytes:
// return a 2-byte UTF-8 character
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0xC0 | (($bytes >> 6) & 0x1F))
. chr(0x80 | ($bytes & 0x3F));
 
case (0xFFFF & $bytes) == $bytes:
// return a 3-byte UTF-8 character
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0xE0 | (($bytes >> 12) & 0x0F))
. chr(0x80 | (($bytes >> 6) & 0x3F))
. chr(0x80 | ($bytes & 0x3F));
}
 
// ignoring UTF-32 for now, sorry
return '';
}
 
/**
* convert a string from one UTF-8 char to one UTF-16 char
*
* Normally should be handled by mb_convert_encoding, but
* provides a slower PHP-only method for installations
* that lack the multibye string extension.
*
* @param string $utf8 UTF-8 character
* @return string UTF-16 character
* @access private
*/
function utf82utf16($utf8)
{
// oh please oh please oh please oh please oh please
if(function_exists('mb_convert_encoding')) {
return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
}
 
switch(strlen($utf8)) {
case 1:
// this case should never be reached, because we are in ASCII range
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return $utf8;
 
case 2:
// return a UTF-16 character from a 2-byte UTF-8 char
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0x07 & (ord($utf8{0}) >> 2))
. chr((0xC0 & (ord($utf8{0}) << 6))
| (0x3F & ord($utf8{1})));
 
case 3:
// return a UTF-16 character from a 3-byte UTF-8 char
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr((0xF0 & (ord($utf8{0}) << 4))
| (0x0F & (ord($utf8{1}) >> 2)))
. chr((0xC0 & (ord($utf8{1}) << 6))
| (0x7F & ord($utf8{2})));
}
 
// ignoring UTF-32 for now, sorry
return '';
}
 
/**
* encodes an arbitrary variable into JSON format
*
* @param mixed $var any number, boolean, string, array, or object to be encoded.
* see argument 1 to Services_JSON() above for array-parsing behavior.
* if var is a strng, note that encode() always expects it
* to be in ASCII or UTF-8 format!
*
* @return mixed JSON string representation of input var or an error if a problem occurs
* @access public
*/
function encode($var)
{
switch (gettype($var)) {
case 'boolean':
return $var ? 'true' : 'false';
 
case 'NULL':
return 'null';
 
case 'integer':
return (int) $var;
 
case 'double':
case 'float':
return (float) $var;
 
case 'string':
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
$ascii = '';
$strlen_var = strlen($var);
 
/*
* Iterate over every character in the string,
* escaping with a slash or encoding to UTF-8 where necessary
*/
for ($c = 0; $c < $strlen_var; ++$c) {
 
$ord_var_c = ord($var{$c});
 
switch (true) {
case $ord_var_c == 0x08:
$ascii .= '\b';
break;
case $ord_var_c == 0x09:
$ascii .= '\t';
break;
case $ord_var_c == 0x0A:
$ascii .= '\n';
break;
case $ord_var_c == 0x0C:
$ascii .= '\f';
break;
case $ord_var_c == 0x0D:
$ascii .= '\r';
break;
 
case $ord_var_c == 0x22:
case $ord_var_c == 0x2F:
case $ord_var_c == 0x5C:
// double quote, slash, slosh
$ascii .= '\\'.$var{$c};
break;
 
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
// characters U-00000000 - U-0000007F (same as ASCII)
$ascii .= $var{$c};
break;
 
case (($ord_var_c & 0xE0) == 0xC0):
// characters U-00000080 - U-000007FF, mask 110XXXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c, ord($var{$c + 1}));
$c += 1;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
 
case (($ord_var_c & 0xF0) == 0xE0):
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}));
$c += 2;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
 
case (($ord_var_c & 0xF8) == 0xF0):
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}));
$c += 3;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
 
case (($ord_var_c & 0xFC) == 0xF8):
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}),
ord($var{$c + 4}));
$c += 4;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
 
case (($ord_var_c & 0xFE) == 0xFC):
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}),
ord($var{$c + 4}),
ord($var{$c + 5}));
$c += 5;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
}
}
 
return '"'.$ascii.'"';
 
case 'array':
/*
* As per JSON spec if any array key is not an integer
* we must treat the the whole array as an object. We
* also try to catch a sparsely populated associative
* array with numeric keys here because some JS engines
* will create an array with empty indexes up to
* max_index which can cause memory issues and because
* the keys, which may be relevant, will be remapped
* otherwise.
*
* As per the ECMA and JSON specification an object may
* have any string as a property. Unfortunately due to
* a hole in the ECMA specification if the key is a
* ECMA reserved word or starts with a digit the
* parameter is only accessible using ECMAScript's
* bracket notation.
*/
 
// treat as a JSON object
if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
$properties = array_map(array($this, 'name_value'),
array_keys($var),
array_values($var));
 
foreach($properties as $property) {
if(Services_JSON::isError($property)) {
return $property;
}
}
 
return '{' . join(',', $properties) . '}';
}
 
// treat it like a regular array
$elements = array_map(array($this, 'encode'), $var);
 
foreach($elements as $element) {
if(Services_JSON::isError($element)) {
return $element;
}
}
 
return '[' . join(',', $elements) . ']';
 
case 'object':
$vars = get_object_vars($var);
 
$properties = array_map(array($this, 'name_value'),
array_keys($vars),
array_values($vars));
 
foreach($properties as $property) {
if(Services_JSON::isError($property)) {
return $property;
}
}
 
return '{' . join(',', $properties) . '}';
 
default:
return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
? 'null'
: new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
}
}
 
/**
* array-walking function for use in generating JSON-formatted name-value pairs
*
* @param string $name name of key to use
* @param mixed $value reference to an array element to be encoded
*
* @return string JSON-formatted name-value pair, like '"name":value'
* @access private
*/
function name_value($name, $value)
{
$encoded_value = $this->encode($value);
 
if(Services_JSON::isError($encoded_value)) {
return $encoded_value;
}
 
return $this->encode(strval($name)) . ':' . $encoded_value;
}
 
/**
* reduce a string by removing leading and trailing comments and whitespace
*
* @param $str string string value to strip of comments and whitespace
*
* @return string string value stripped of comments and whitespace
* @access private
*/
function reduce_string($str)
{
$str = preg_replace(array(
 
// eliminate single line comments in '// ...' form
'#^\s*//(.+)$#m',
 
// eliminate multi-line comments in '/* ... */' form, at start of string
'#^\s*/\*(.+)\*/#Us',
 
// eliminate multi-line comments in '/* ... */' form, at end of string
'#/\*(.+)\*/\s*$#Us'
 
), '', $str);
 
// eliminate extraneous space
return trim($str);
}
 
/**
* decodes a JSON string into appropriate variable
*
* @param string $str JSON-formatted string
*
* @return mixed number, boolean, string, array, or object
* corresponding to given JSON input string.
* See argument 1 to Services_JSON() above for object-output behavior.
* Note that decode() always returns strings
* in ASCII or UTF-8 format!
* @access public
*/
function decode($str)
{
$str = $this->reduce_string($str);
 
switch (strtolower($str)) {
case 'true':
return true;
 
case 'false':
return false;
 
case 'null':
return null;
 
default:
$m = array();
 
if (is_numeric($str)) {
// Lookie-loo, it's a number
 
// This would work on its own, but I'm trying to be
// good about returning integers where appropriate:
// return (float)$str;
 
// Return float or int, as appropriate
return ((float)$str == (integer)$str)
? (integer)$str
: (float)$str;
 
} elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
// STRINGS RETURNED IN UTF-8 FORMAT
$delim = substr($str, 0, 1);
$chrs = substr($str, 1, -1);
$utf8 = '';
$strlen_chrs = strlen($chrs);
 
for ($c = 0; $c < $strlen_chrs; ++$c) {
 
$substr_chrs_c_2 = substr($chrs, $c, 2);
$ord_chrs_c = ord($chrs{$c});
 
switch (true) {
case $substr_chrs_c_2 == '\b':
$utf8 .= chr(0x08);
++$c;
break;
case $substr_chrs_c_2 == '\t':
$utf8 .= chr(0x09);
++$c;
break;
case $substr_chrs_c_2 == '\n':
$utf8 .= chr(0x0A);
++$c;
break;
case $substr_chrs_c_2 == '\f':
$utf8 .= chr(0x0C);
++$c;
break;
case $substr_chrs_c_2 == '\r':
$utf8 .= chr(0x0D);
++$c;
break;
 
case $substr_chrs_c_2 == '\\"':
case $substr_chrs_c_2 == '\\\'':
case $substr_chrs_c_2 == '\\\\':
case $substr_chrs_c_2 == '\\/':
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
$utf8 .= $chrs{++$c};
}
break;
 
case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
// single, escaped unicode character
$utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
. chr(hexdec(substr($chrs, ($c + 4), 2)));
$utf8 .= $this->utf162utf8($utf16);
$c += 5;
break;
 
case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
$utf8 .= $chrs{$c};
break;
 
case ($ord_chrs_c & 0xE0) == 0xC0:
// characters U-00000080 - U-000007FF, mask 110XXXXX
//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 2);
++$c;
break;
 
case ($ord_chrs_c & 0xF0) == 0xE0:
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 3);
$c += 2;
break;
 
case ($ord_chrs_c & 0xF8) == 0xF0:
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 4);
$c += 3;
break;
 
case ($ord_chrs_c & 0xFC) == 0xF8:
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 5);
$c += 4;
break;
 
case ($ord_chrs_c & 0xFE) == 0xFC:
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 6);
$c += 5;
break;
 
}
 
}
 
return $utf8;
 
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
// array, or object notation
 
if ($str{0} == '[') {
$stk = array(SERVICES_JSON_IN_ARR);
$arr = array();
} else {
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$stk = array(SERVICES_JSON_IN_OBJ);
$obj = array();
} else {
$stk = array(SERVICES_JSON_IN_OBJ);
$obj = new stdClass();
}
}
 
array_push($stk, array('what' => SERVICES_JSON_SLICE,
'where' => 0,
'delim' => false));
 
$chrs = substr($str, 1, -1);
$chrs = $this->reduce_string($chrs);
 
if ($chrs == '') {
if (reset($stk) == SERVICES_JSON_IN_ARR) {
return $arr;
 
} else {
return $obj;
 
}
}
 
//print("\nparsing {$chrs}\n");
 
$strlen_chrs = strlen($chrs);
 
for ($c = 0; $c <= $strlen_chrs; ++$c) {
 
$top = end($stk);
$substr_chrs_c_2 = substr($chrs, $c, 2);
 
if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
// found a comma that is not inside a string, array, etc.,
// OR we've reached the end of the character list
$slice = substr($chrs, $top['where'], ($c - $top['where']));
array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
 
if (reset($stk) == SERVICES_JSON_IN_ARR) {
// we are in an array, so just push an element onto the stack
array_push($arr, $this->decode($slice));
 
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
// we are in an object, so figure
// out the property name and set an
// element in an associative array,
// for now
$parts = array();
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
// "name":value pair
$key = $this->decode($parts[1]);
$val = $this->decode($parts[2]);
 
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$obj[$key] = $val;
} else {
$obj->$key = $val;
}
} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
// name:value pair, where name is unquoted
$key = $parts[1];
$val = $this->decode($parts[2]);
 
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$obj[$key] = $val;
} else {
$obj->$key = $val;
}
}
 
}
 
} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
// found a quote, and we are not inside a string
array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
//print("Found start of string at {$c}\n");
 
} elseif (($chrs{$c} == $top['delim']) &&
($top['what'] == SERVICES_JSON_IN_STR) &&
((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
// found a quote, we're in a string, and it's not escaped
// we know that it's not escaped becase there is _not_ an
// odd number of backslashes at the end of the string so far
array_pop($stk);
//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
 
} elseif (($chrs{$c} == '[') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a left-bracket, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
//print("Found start of array at {$c}\n");
 
} elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
// found a right-bracket, and we're in an array
array_pop($stk);
//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
 
} elseif (($chrs{$c} == '{') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a left-brace, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
//print("Found start of object at {$c}\n");
 
} elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
// found a right-brace, and we're in an object
array_pop($stk);
//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
 
} elseif (($substr_chrs_c_2 == '/*') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a comment start, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
$c++;
//print("Found start of comment at {$c}\n");
 
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
// found a comment end, and we're in one now
array_pop($stk);
$c++;
 
for ($i = $top['where']; $i <= $c; ++$i)
$chrs = substr_replace($chrs, ' ', $i, 1);
 
//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
 
}
 
}
 
if (reset($stk) == SERVICES_JSON_IN_ARR) {
return $arr;
 
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
return $obj;
 
}
 
}
}
}
 
/**
* @todo Ultimately, this should just call PEAR::isError()
*/
function isError($data, $code = null)
{
if (class_exists('pear')) {
return PEAR::isError($data, $code);
} elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
is_subclass_of($data, 'services_json_error'))) {
return true;
}
 
return false;
}
}
 
if (class_exists('PEAR_Error')) {
 
class Services_JSON_Error extends PEAR_Error
{
function Services_JSON_Error($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null)
{
parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
}
}
 
} else {
 
/**
* @todo Ultimately, this class shall be descended from PEAR_Error
*/
class Services_JSON_Error
{
function Services_JSON_Error($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null)
{
 
}
}
 
}
?>
/trunk/services/bibliotheque/Maillage.php
New file
0,0 → 1,151
<?php
 
 
class Maillage {
private $bbox = array();
private $zoom = '';
private $source = '';
private $indexLongitude = array();
private $indexLatitude = array();
private $mailles = array();
private $bdd = null;
public function __construct($bbox, $zoom, $source) {
$this->bbox = $this->calculerLimiteBboxGlobale($bbox);
$this->zoom = $zoom;
$this->source = $source;
$this->indexLongitude = array();
$this->indexLatitude = array();
$this->mailles = array();
}
private function calculerLimiteBboxGlobale($bbox) {
$bboxGlobale = $bbox[0];
for ($index = 1; $index < count($bbox); $index ++) {
if ($bbox[$index]['ouest'] < $bboxGlobale['ouest']) {
$bboxGlobale['ouest'] = $bbox[$index]['ouest'];
}
if ($bbox[$index]['sud'] < $bboxGlobale['sud']) {
$bboxGlobale['sud'] = $bbox[$index]['sud'];
}
if ($bbox[$index]['est'] > $bboxGlobale['est']) {
$bboxGlobale['est'] = $bbox[$index]['est'];
}
if ($bbox[$index]['nord'] > $bboxGlobale['nord']) {
$bboxGlobale['nord'] = $bbox[$index]['nord'];
}
}
return $bboxGlobale;
}
public function genererMaillesVides() {
$this->recupererIndexMaillesDansBbox();
foreach ($this->indexLatitude as $indexLat => $intervalleLat) {
$ligne = array();
foreach ($this->indexLongitude as $indexLng => $intervalleLng) {
$ligne[] = new Maille($intervalleLat[0], $intervalleLng[0], $intervalleLat[1],
$intervalleLng[1], $indexLat, $indexLng);
}
$this->mailles[] = $ligne;
}
}
private function recupererIndexMaillesDansBbox() {
$conditionsLongitude = "";
if ($this->bbox['ouest'] > $this->bbox['est']) {
$conditionsLongitude = "NOT(debut>=".$this->bbox['ouest']." AND fin<=".$this->bbox['est'].")";
} else {
$conditionsLongitude = "fin>=".$this->bbox['ouest']." AND debut <=".$this->bbox['est'];
}
$requete =
"SELECT axe, position, debut, fin FROM mailles_index WHERE zoom=".$this->zoom." ".
"AND (".
"(axe='lat' AND fin>=".$this->bbox['sud']." AND debut<=".$this->bbox['nord'].") ".
"OR (axe='lng' AND {$conditionsLongitude})".
") ORDER BY axe, position";
$indexMailles = $this->getBdd()->recupererTous($requete);
foreach ($indexMailles as $index) {
if ($index['axe'] == 'lng') {
$this->indexLongitude[$index['position']] = array($index['debut'], $index['fin']);
} else {
$this->indexLatitude[$index['position']] = array($index['debut'], $index['fin']);
}
}
}
private function getBdd() {
if (is_null($this->bdd)) {
$this->bdd = new Bdd();
}
$nomBdd = Config::get('bdd_nom_eflore');
$this->bdd->requeter("USE ".$nomBdd);
return $this->bdd;
}
public function ajouterStations(& $stations) {
foreach ($stations as $station) {
$longitude = $station['longitude'];
$latitude = $station['latitude'];
list($indexLongitude, $indexLatitude) = $this->rechercherIndexMaille($longitude, $latitude);
$this->mailles[$indexLatitude][$indexLongitude]->ajouterStation($station, $this->source);
}
}
public function ajouterMailles(& $mailles) {
foreach ($mailles as $maille) {
$longitude = ($maille['ouest'] + $maille['est']) / 2;
$latitude = ($maille['sud'] + $maille['nord']) / 2;
list($indexLongitude, $indexLatitude) = $this->rechercherIndexMaille($longitude, $latitude);
$this->mailles[$indexLatitude][$indexLongitude]->combinerMailles($maille, $this->source);
}
}
private function rechercherIndexMaille($longitude, $latitude) {
$indexLatitude = 0;
$indexLongitude = 0;
while ($indexLatitude < count($this->indexLatitude) - 1
&& $this->mailles[$indexLatitude][0]->getLatitudeNord() < $latitude) {
$indexLatitude ++;
}
while ($indexLongitude < count($this->indexLongitude) - 1
&& $this->mailles[$indexLatitude][$indexLongitude]->getLongitudeEst() < $longitude) {
$indexLongitude ++;
}
return array($indexLongitude, $indexLatitude);
}
 
public function formaterSortie() {
$mailles_resume = array();
foreach ($this->mailles as $ligne) {
foreach ($ligne as $maille) {
$nombreStations = $maille->getNombrestations();
if ($nombreStations > 0) {
$mailles_resume[] = array(
'type_site' => 'MAILLE',
'sud' => $maille->getLatitudeSud(),
'ouest' => $maille->getLongitudeOuest(),
'nord' => $maille->getLatitudeNord(),
'est' => $maille->getLongitudeEst(),
'stations' => $maille->getStations(),
'observations' => $maille->getObservations()
);
}
}
}
if (count($mailles_resume) == 0 || count($mailles_resume[0]) == 0)
return array();
return $mailles_resume;
}
 
}
 
?>
/trunk/services/bibliotheque/ReponseHttp.php
New file
0,0 → 1,87
<?php
 
class ReponseHttp {
 
private $resultatService = null;
private $erreurs = array();
 
public function __construct() {
$this->resultatService = new ResultatService();
if (function_exists('json_decode') == false){
require_once (dirname(__FILE__).'/JSON.php');
function json_decode($content, $assoc = false){
if ($assoc) {
$json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
} else {
$json = new Services_JSON;
}
return $json->decode($content);
}
}
 
if ( !function_exists('json_encode') ){
function json_encode($content){
$json = new Services_JSON;
return $json->encode($content);
}
}
}
 
public function setResultatService($resultat) {
if (!($resultat instanceof ResultatService)) {
$this->resultatService->corps = $resultat;
} else {
$this->resultatService = $resultat;
}
}
 
public function getCorps() {
if ($this->etreEnErreur()) {
$this->resultatService->corps = $this->erreurs[0]['message'];
} else {
$this->transformerReponseCorpsSuivantMime();
}
return $this->resultatService->corps;
}
 
public function ajouterErreur(Exception $e) {
$this->erreurs[] = array('entete' => $e->getCode(), 'message' => $e->getMessage());
}
 
public function emettreLesEntetes() {
$enteteHttp = new EnteteHttp();
if ($this->etreEnErreur()) {
$enteteHttp->code = $this->erreurs[0]['entete'];
$enteteHttp->mime = 'text/html';
} else {
$enteteHttp->encodage = $this->resultatService->encodage;
$enteteHttp->mime = $this->resultatService->mime;
}
header("Content-Type: $enteteHttp->mime; charset=$enteteHttp->encodage");
RestServeur::envoyerEnteteStatutHttp($enteteHttp->code);
}
 
private function etreEnErreur() {
$enErreur = false;
if (count($this->erreurs) > 0) {
$enErreur = true;
}
return $enErreur;
}
 
private function transformerReponseCorpsSuivantMime() {
switch ($this->resultatService->mime) {
case 'application/json' :
if (isset($_GET['callback'])) {
$contenu = $_GET['callback'].'('.json_encode($this->resultatService->corps).');';
} else {
$contenu = json_encode($this->resultatService->corps);
}
$this->resultatService->corps = $contenu;
break;
}
}
 
}
 
?>
/trunk/services/bibliotheque/VerificateurParametres.php
New file
0,0 → 1,474
<?php
 
 
/**
* Classe commune a tous les services de ce projet qui va analyser et rechercher des erreurs
* sur les valeurs passees en parametres lors d'un appel a ces web services.
*
* Les parametres suivants sont traites :
* - zoom : le niveau de zoom sur la carte (API cartographique client)
* On va verifier que c'est un nombre entier compris entre une valeur minimale et une valeur maximale
*
* - bbox : rectangle dont les bords delimitent en coordonnees l'espace de recherche de donnees spatiales
* L'ordre des valeurs est le suivant : ouest, sud, est, nord
* On va verifier que c'est une serie de quatre nombre decimaux delimites par des virgules
* et compris dans l'espace representant le monde a partir du systeme de projection WGS84 (EPSG:4326)
*
* - stations : liste de points d'observations. C'est une serie de stations qui est passee en parametres
* de cette maniere, separees entre elles par un seperateur vertical |. Chaque station est decrite
* par sa source de donnees, le type de site et ses coordonnees longitude et latitude.
*
* - referentiel : referentiel taxonomique a utiliser. On peut passer aussi bien en parametres
* son nom court que son nom complet (incluant le numero de version)
* On va verifier la disponibilite du referentiel pour ce service
*
* - num_taxon : numero taxonomique d'une espece
* - nn : numero nomenclatural d'une espece
* On va rechercher sa presence dans les referentiels disponibles
* (les informations principales sur ce taxon seront renvoyees)
*
* - dept : une liste de numeros de departements separees entre eux par des virgules
* On va verifier que chaque numero est un nombre entier et represente un code de departement valide
*
* - auteur : l'auteur de l'observation
*
* - date_debut et date_fin : intervalle de dates d'observation. On verifie que ce sont des dates valides
* et que date_debut <= date_fin. Le programme peut accepter la presence d'un seul de ces deux
* parametres : soit une date de debut, soit une date de fin
*
* - nb_jours : valeur entiere qui indique de recuperer les observations effectuees ou transmises
* sur les derniers jours avant la date d'execution du script
*
* La fonction principale de verification des parametres va parcourir tous les parametres, et verifier
* pour chacun d'eux la validite de leurs valeurs. Dans le cas ou une valeur anormale est detectee
* ou qu'elle se trouve en dehors de l'intervalle des resultats acceptes, une liste de messages d'erreur
* sera generee et mise a jour.
*
* Le resultat final de la verfication peut entrainer deux cas d'utilisation possibles. Si des messages
* d'erreurs ont ete generes durant la verification, ils sont regroupes en un seul message pour lever
* une exception qui sera interpretee par la classe appelante. Dans le cas ou la verification n'a rien
* rencontre d'anormal, une fonction renverra la liste des parametres valides utilisables
* pour des recherches de donnees pour la suite du traitement pour le service.
*
* @package framework-0.3
* @author Alexandre GALIBERT <alexandre.galibert@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 2013 Tela Botanica (accueil@tela-botanica.org)
*
*/
 
class VerificateurParametres {
private $parametres = array();
private $validation = null;
private $erreurs = array();
private $dateTraitee = false;
private $bboxMonde = null;
public function __construct($parametres) {
foreach ($parametres as $nomParametre => $valeur) {
$this->parametres[$nomParametre] = $valeur;
}
$this->bboxMonde = array(
'ouest' => floatval(Config::get('carte.limite_ouest')),
'est' => floatval(Config::get('carte.limite_est')),
'sud' => floatval(Config::get('carte.limite_sud')),
'nord' => floatval(Config::get('carte.limite_nord'))
);
$this->validation = new StdClass();
}
public function verifierParametres() {
foreach ($this->parametres as $nomParametre => $valeur) {
switch ($nomParametre) {
case 'zoom' : $this->traiterParametreZoom($valeur);
break;
case 'bbox' : $this->traiterParametreBbox($valeur);
break;
case 'stations' : $this->traiterParametreStations($this->parametres['stations']);
break;
case 'dept' : $this->traiterParametreDepartement($valeur);
break;
case 'auteur' : $this->traiterParametreAuteur($valeur);
break;
case 'referentiel' : $this->traiterParametreReferentiel($valeur);
break;
case 'num_taxon' : $this->traiterParametreTaxon($valeur);
break;
case 'nn' : $this->traiterParametreNomenclatural($valeur);
break;
case 'type_site' : $this->traiterParametreTypeSite($valeur);
break;
case 'nb_jours' : $this->traiterParametreNbJours($valeur);
break;
case 'date_debut' :
case 'date_fin' : {
$dateDebut = isset($this->parametres['date_debut']) ? $this->parametres['date_debut'] : null;
$dateFin = isset($this->parametres['date_fin']) ? $this->parametres['date_fin'] : null;
if (!$this->dateTraitee) {
$this->traiterParametresDate($dateDebut, $dateFin);
$this->dateTraitee = true;
}
break;
}
case 'format' : $this->validation->format = strtolower($valeur); break;
// autres parametres ==> les ignorer
default : break;
}
}
$this->verifierPresenceParametreSpatial();
}
private function ajouterErreur($messageErreur) {
$this->erreurs[] = $messageErreur;
}
public function renvoyerResultatVerification() {
return $this->validation;
}
public function contienterreurs() {
return count($this->erreurs);
}
public function leverException() {
$messagesErreur = "Les erreurs suivantes ont été rencontrées : \n".
implode("\n", $this->erreurs);
throw new Exception($messagesErreur, RestServeur::HTTP_CODE_MAUVAISE_REQUETE);
}
// ------------------------------------------------------------------------- //
// Fonctions de verification de parametres et detection de valeurs anormales //
// ------------------------------------------------------------------------- //
private function traiterParametreZoom($zoom) {
$zoom = intval($zoom);
$mondeZoom = array(
'min' => intval(Config::get('carte.zoom_minimal')),
'max' => intval(Config::get('carte.zoom_maximal'))
);
if ($zoom < $mondeZoom['min'] || $zoom > $mondeZoom['max']) {
$message = 'Niveau de zoom non reconnu par le service. Il doit être compris entre '.
$mondeZoom['min'].' et '.$mondeZoom['max'];
$this->ajouterErreur($message);
} else {
$this->validation->zoom = $zoom;
}
}
private function traiterParametreBbox($chaineBbox) {
$listeBbox = explode('|', trim($chaineBbox));
$critereBbox = array();
foreach ($listeBbox as $bbox) {
$bboxVerifiee = $this->verifierCoordonneesBbox($bbox);
if (!is_null($bboxVerifiee)) {
$critereBbox[] = $bboxVerifiee;
}
}
$this->validation->bbox = $critereBbox;
}
private function verifierCoordonneesBbox($bbox) {
$bboxVerifiee = null;
// verifier que la chaine de caracteres $bbox est une serie de chaque nombre decimaux
// separes entre eux par une virgule
if (preg_match('/^(-?\d{1,3}(.\d+)?,){3}(-?\d{1,3}(.\d+)?)$/', $bbox) == 0) {
$message = "Format de saisie des coordonnees de la bounding box non valide. Le service ".
"n'accepte seulement qu'une serie de 4 nombre décimaux séparés par des virgules.";
$this->ajouterErreur($message);
} else {
$coordonnees = explode(',', $bbox);
// index du tableau des coordonnees : ouest/sud/est/nord
$nomsIndexBbox = array("ouest", "sud", "est", "nord");
$bbox = array();
for ($i = 0; $i < count($coordonnees); $i ++) {
$bbox[$nomsIndexBbox[$i]] = $coordonnees[$i];
}
// verifier que les coordonnees de chaque bord de la bbox sont valides
if ($this->estUneBboxValide($bbox)) {
$bboxVerifiee = $bbox;
} else {
$message = "Certaines coordonnées de la bounding box sont situés en dehors des limites ".
"de notre monde";
$this->ajouterErreur($message);
}
}
return $bboxVerifiee;
}
private function estUneBboxValide($bbox) {
$monde = $this->bboxMonde;
return (floatval($bbox['ouest']) >= $monde['ouest'] && floatval($bbox['ouest']) <= $monde['est']
&& floatval($bbox['est']) >= $monde['ouest'] && floatval($bbox['est']) <= $monde['est']
&& floatval($bbox['nord']) >= $monde['sud'] && floatval($bbox['nord']) <= $monde['nord']
&& floatval($bbox['sud']) >= $monde['sud'] && floatval($bbox['sud']) <= $monde['nord']);
}
private function traiterParametreStations($listeStations) {
$stations = explode('|', trim($listeStations));
$critereStations = array();
foreach ($stations as $station) {
preg_match("/([a-z]+):([a-z]+):(-?\d{1,3}.\d+),(-?\d{1,3}.\d+)/", $station, $matches);
if (count($matches) < 5) {
$message = "Les données transmises sur la station à interroger sont incomplètes. ".
"Le format suivant doit être respecté : source:type_site:longitude:latitude";
$this->ajouterErreur($message);
} else {
$matches = array_splice($matches, 1, count($matches));
$this->verifierCoordonneesStation($matches);
$this->verifierSourceStation($matches[0]);
$this->verifierTypeStation($matches[1]);
$critereStations[] = $matches;
}
}
$this->validation->stations = $critereStations;
}
private function verifierCoordonneesStation(& $station) {
$longitude = floatval($station[2]);
$latitude = floatval($station[3]);
if ($this->sontDesCoordonneesValides($longitude, $latitude)) {
$station[2] = $latitude;
$station[3] = $longitude;
} else {
$message = "Les coordonnees du point passées en parametres sont en dehors des limites de notre monde";
$this->ajouterErreur($message);
}
}
private function sontDesCoordonneesValides($longitude, $latitude) {
$monde = $this->bboxMonde;
return (floatval($longitude) >= $monde['ouest'] && floatval($longitude) <= $monde['est']
&& floatval($latitude) >= $monde['sud'] && floatval($latitude) <= $monde['nord']);
}
private function verifierTypeStation($typeStation) {
$typeStationsValides = array('station', 'commune');
if (!in_array($typeStation, $typeStationsValides)) {
$message = "'$typeStation' n'est pas un type de station reconnu. Sont acceptés seulement 'station' et 'commune'.";
$this->ajouterErreur($message);
}
}
private function verifierSourceStation($source) {
$sourcesARequeter = explode(',', trim($this->parametres['source']));
if (!in_array($source, $sourcesARequeter)) {
$message = "La source '$source' n'est pas listée dans le paramètre source de l'URL (sont disponibles ".
implode(',', $sourcesARequeter).").";
$this->ajouterErreur($message);
}
}
private function traiterParametreDepartement($numeroDepartement) {
if ($numeroDepartement != '*') {
$departements = explode(',', trim($numeroDepartement));
foreach ($departements as $departement) {
if($this->estUnCodeDepartementValide($departement)) {
$this->validation->departement[] = $departement;
} else {
$message = "Code de département non valide";
$this->ajouterErreur($message);
}
}
}
}
private function estUnCodeDepartementValide($departement) {
// expression reguliere pour verifier que c'est un nombre entier a 2 ou 3 chiffres
$estUnDepartementValide = true;
if ($departement == '2A' || $departement == '2B') {
$estUnDepartementValide = true;
} elseif (preg_match('/^\d{2,3}$/', $departement) != 1) {
$estUnDepartementValide = false;
} else {
if ((intval($departement) < 1 || intval($departement) > 95)
&& (intval($departement) < 971 || intval($departement) > 978)) {
$estUnDepartementValide = false;
}
}
return $estUnDepartementValide;
}
private function traiterParametreAuteur($auteur) {
if ($auteur != '*') {
$this->validation->auteur = trim($auteur);
}
}
private function traiterParametreTypeSite($typeSite) {
$this->validation->typeSite = strtolower(trim($typeSite));
}
private function traiterParametreReferentiel($referentiel) {
if (!isset($this->validation->referentiel) && $referentiel != '*') {
$referentielAUtiliser = $this->affecterNomCompletReferentiel($referentiel);
if (is_null($referentielAUtiliser)) {
$message = "Le référentiel demandé n'est pas reconnu par le service.";
$this->ajouterErreur($message);
} else {
$this->validation->referentiel = $referentielAUtiliser;
}
}
}
private function affecterNomCompletReferentiel($referentiel) {
$referentielAUtiliser = null;
$listeReferentiels = Referentiel::recupererListeReferentielsDisponibles();
foreach ($listeReferentiels as $nomReferentiel) {
$nomCourtReferentiel = current(explode('_', $nomReferentiel));
if ($referentiel == $nomCourtReferentiel || $referentiel == $nomReferentiel) {
$referentielAUtiliser = $nomReferentiel;
break;
}
}
return $referentielAUtiliser;
}
private function traiterParametreTaxon($numeroTaxon) {
if ($numeroTaxon != '*') {
$listeTaxons = explode(',', $numeroTaxon);
foreach ($listeTaxons as $nt) {
$taxon = null;
if (isset($this->validation->referentiel)) {
$taxon = $this->renvoyerTaxonDansReferentiel($nt, 'nt', $this->validation->referentiel);
} else {
$taxon = $this->rechercherTaxonDansReferentiels($nt, 'nt');
}
if (is_null($taxon)) {
$message = "Le numéro de taxon n'a pas permis de retrouver le taxon associé.";
$this->ajouterErreur($message);
} else {
$this->ajouterTaxonAListe($taxon);
$this->validation->referentiel = $taxon['referentiel'];
}
}
}
}
private function traiterParametreNomenclatural($numeroNomenclatural) {
if ($numeroNomenclatural != '*') {
$listeTaxons = explode(',', $numeroNomenclatural);
foreach ($listeTaxons as $nn) {
$taxon = null;
if (isset($this->validation->referentiel)) {
$taxon = $this->renvoyerTaxonDansReferentiel($nn, 'nn', $this->validation->referentiel);
} else {
$taxon = $this->rechercherTaxonDansReferentiels($nn, 'nn');
}
if (is_null($taxon)) {
$message = "Le numéro nomenclatural n'a pas permis de retrouver le taxon associé.";
$this->ajouterErreur($message);
} else {
$this->ajouterTaxonAListe($taxon);
$this->validation->referentiel = $taxon['referentiel'];
}
}
}
}
private function rechercherTaxonDansReferentiels($numeroTaxon, $typeNumero) {
$taxon = null;
$listeReferentiels = Referentiel::recupererListeReferentielsDisponibles();
foreach ($listeReferentiels as $nomReferentiel) {
$taxon = $this->renvoyerTaxonDansReferentiel($numeroTaxon, $typeNumero, $nomReferentiel);
if (!is_null($taxon)) {
break;
}
}
return $taxon;
}
private function renvoyerTaxonDansReferentiel($numeroTaxon, $typeNumero, $nomReferentiel) {
$referentiel = new Referentiel($nomReferentiel);
$referentiel->chargerTaxon($typeNumero, $numeroTaxon);
$taxon = $referentiel->renvoyerTaxon();
return $taxon;
}
private function ajouterTaxonAListe($taxon) {
if (!isset($this->validation->taxon)) {
$this->validation->taxon = array($taxon);
} elseif (!in_array($taxon, $this->validation->taxon)) {
$this->validation->taxon[] = $taxon;
}
}
private function traiterParametresDate($dateDebut, $dateFin) {
$statutValidite = $this->verifierValiditeDate($dateDebut, 'début')
+ $this->verifierValiditeDate($dateFin, 'fin');
if ($statutValidite == 2) {
if (!is_null($dateDebut) && !is_null($dateFin) && $dateDebut > $dateFin) {
$message = "Intervalle de dates incorrect : date de fin avant la date de début";
$this->ajouterErreur($message);
} else {
$this->validation->dateDebut = $dateDebut;
$this->validation->dateFin = $dateFin;
}
}
}
private function verifierValiditeDate(& $date, $position) {
$statutValidite = is_null($date) ? 1 : 0;
$moisParDefaut = $position == 'début' ? 1 : 12;
$jourParDefaut = $position == 'début' ? 1 : 31;
if (!is_null($date)) {
$split = explode("-", $date);
$annee = intval($split[0]);
$mois = isset($split[1]) ? intval($split[1]) : $moisParDefaut;
$jour = isset($split[2]) ? intval($split[2]) : $jourParDefaut;
if (!$this->estDateValide($jour, $mois, $annee)) {
$message = "Date de {$position} saisie non valide";
$this->ajouterErreur($message);
} else {
$date = $annee."-".(($mois<10)?"0".$mois:$mois)."-".(($jour<10)?"0".$jour:$jour);
$dateDuJour = date('Y-m-d');
if ($date > $dateDuJour) {
$message = "La date de {$position} saisie postérieure à la date du jour : {$dateDuJour}";
$this->ajouterErreur($message);
} else {
$statutValidite = 1;
}
}
}
return $statutValidite;
}
private function estDateValide($jour, $mois, $annee) {
$estBissextile = (($annee % 4 == 0 && $annee % 100 != 0) || ($annee % 400 == 0));
$dureeFevrier = $estBissextile ? 29 : 28;
$dureeMois = array(1 => 31, 2 => $dureeFevrier, 3 => 31, 4 => 30, 5 => 31, 6 => 30, 7 => 31,
8 => 31, 9 => 30, 10 => 31, 11 => 30, 12 => 31);
return ($annee >= 1900 && $mois >= 1 && $mois <= 12 && $jour >= 1 && $jour <= $dureeMois[$mois]);
}
private function verifierPresenceParametreSpatial() {
$presenceParametreSpatial = false;
if (isset($this->parametres['bbox'])
|| (isset($this->parametres['stations']))) {
$presenceParametreSpatial = true;
}
if ($presenceParametreSpatial == false) {
$message = "Aucune coordonnée n'a été saisie";
$this->ajouterErreur($message);
}
}
private function traiterParametreNbJours($nbJours) {
// verifier que c'est un nombre entier positif (avec expression reguliere)
if (preg_match('/^\d+$/', $nbJours) != 1) {
$message = "La valeur passée pour le nombre de jours doit être un entier positif.";
$this->ajouterErreur($message);
} elseif ($nbJours > 0) {
$this->validation->nbJours = intval($nbJours);
}
}
}
 
?>
/trunk/services/bibliotheque/FormateurJson.php
New file
0,0 → 1,166
<?php
 
 
class FormateurJson {
public function __construct() {}
public function formaterStations($stations) {
$objetJSON = new StdClass();
$objetJSON->type = "FeatureCollection";
$objetJSON->stats = new StdClass();
$objetJSON->stats->source = array();
$objetJSON->stats->formeDonnees = '';
if (count($stations) > 0) {
$objetJSON->stats->formeDonnees = ($stations[0]['type_site'] == 'MAILLE') ? 'maille' : 'point';
}
$objetJSON->stats->stations = 0;
$objetJSON->stats->observations = 0;
$objetJSON->features = array();
foreach ($stations as $station) {
$stationJSON = null;
if ($station['type_site'] == 'MAILLE') {
$stationJSON = $this->formaterMaille($station);
$objetJSON->stats->stations += array_sum($station['stations']);
$objetJSON->stats->observations += array_sum($station['observations']);
} else {
$stationJSON = $this->formaterPoint($station);
$objetJSON->stats->stations ++;
$objetJSON->stats->observations += $station['observations'];
}
$objetJSON->features[] = $stationJSON;
$this->ajouterSourcesAuxStats($station, $objetJSON->stats);
}
return $objetJSON;
}
private function ajouterSourcesAuxStats($station, & $stats) {
if ($station['type_site'] == 'MAILLE') {
foreach ($station['stations'] as $source => $nombreStations) {
if (!in_array($source, $stats->source)) {
$stats->source[] = $source;
}
}
} else {
if (!in_array($station['source'], $stats->source)) {
$stats->source[] = $station['source'];
}
}
}
private function formaterPoint(& $station) {
$json = new StdClass();
$json->type = "Feature";
$json->geometry = new StdClass();
$json->properties = new StdClass();
$json->geometry->type = "Point";
$json->properties->source = $station['source'];
$json->properties->typeSite = $station['type_site'];
$json->geometry->coordinates = array($station['latitude'], $station['longitude']);
$codeInsee = isset($station['code_insee']) ? $station['code_insee'] : substr($station['ce_zone_geo'],-5);
$codeDepartement = $this->extraireCodeDepartement($codeInsee);
$nom = '';
if ($station['source'] != 'floradata') {
$json->properties->nom = trim($station['nom'])." ({$codeDepartement})";
} else {
$station['station'] = (is_null($station['station']) || strlen(trim($station['station'])) == 0)
? $station['zone_geo'] : $station['station'];
$nom = $station['type_site'] == 'COMMUNE' ? $station['zone_geo'] : $station['station'];
$json->properties->nom = trim($nom)." ({$codeDepartement})";
}
return $json;
}
private function construireNomStation(& $station) {
}
private function extraireCodeDepartement($codeInsee) {
$codeDepartement = substr($codeInsee, 0 ,2);
if (intval($codeDepartement) > 95) {
$codeDepartement = substr($codeInsee, 0 ,3);
}
return $codeDepartement;
}
private function formaterMaille($maille) {
$json = new StdClass();
$json->type = "Feature";
$json->geometry = new StdClass();
$json->geometry->type = "Polygon";
$json->geometry->coordinates = array(
array(floatval($maille['sud']), floatval($maille['ouest'])),
array(floatval($maille['sud']), floatval($maille['est'])),
array(floatval($maille['nord']), floatval($maille['est'])),
array(floatval($maille['nord']), floatval($maille['ouest'])),
array(floatval($maille['sud']), floatval($maille['ouest']))
);
$json->properties = new StdClass();
$json->properties->source = array();
foreach ($maille['stations'] as $source => $nombreStations) {
$json->properties->source[] = $source;
}
$json->properties->typeSite = 'MAILLE';
$json->properties->stations = $maille['stations'];
$json->properties->observations = $maille['observations'];
return $json;
}
public function formaterObservations($observations) {
//print_r($observations); exit;
$objetJSON = new StdClass();
$objetJSON->site = trim($observations[0]['nom_station']);
$objetJSON->total = count($observations);
$objetJSON->observations = array();
foreach ($observations as $observation) {
$this->concatenerLieuObservation($observation);
$observationJson = new stdClass();
foreach ($observation as $colonne => $valeur) {
if ($colonne == 'nom_referentiel') {
$observationJson->urlEflore = $this->genererUrlFicheEflore($observation);
} else {
$observationJson->$colonne = is_string($valeur) ? trim($valeur) : $valeur;
}
}
$this->formaterDateObservation($observationJson);
$objetJSON->observations[] = $observationJson;
}
return $objetJSON;
}
private function formaterDateObservation(& $observation) {
if (isset($observation->date) && strlen($observation->date) > 4) {
$dateFormatee = preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$3/$2/$1', $observation->date);
$observation->date = $dateFormatee;
}
}
private function genererUrlFicheEflore(& $observation) {
$url = null;
if (strstr($observation['nom_referentiel'], 'bdtfx') !== false) {
$url = 'http://www.tela-botanica.org/bdtfx-nn-'.$observation['nn'];
}
return $url;
}
private function concatenerLieuObservation(& $observation) {
$lieux = array();
if (isset($observation['lieudit']) && !is_null($observation['lieudit'])) {
$lieux[] = $observation['lieudit'];
}
if (isset($observation['milieu']) && !is_null($observation['milieu'])) {
$lieux[] = $observation['milieu'];
}
unset($observation['lieudit']);
unset($observation['milieu']);
$observation['lieu'] = implode(', ', $lieux);
}
}
 
?>
/trunk/services/bibliotheque/Maille.php
New file
0,0 → 1,95
<?php
 
class Maille {
private $latitudeSud;
private $longitudeOuest;
private $latitudeNord;
private $longitudeEst;
private $indexLatitude;
private $indexLongitude;
private $stations = array();
private $observations = array();
public function __construct($sud, $ouest, $nord, $est, $indexLat, $indexLng) {
$this->latitudeSud = $sud;
$this->longitudeOuest = $ouest;
$this->latitudeNord = $nord;
$this->longitudeEst = $est;
$this->indexLatitude = $indexLat;
$this->indexLongitude = $indexLng;
}
public function ajouterStation($station, $source) {
if (!array_key_exists($source, $this->stations)) {
$this->stations[$source] = 1;
$this->observations[$source] = $station['observations'];
} else {
$this->stations[$source] += 1;
$this->observations[$source] += intval($station['observations']);
}
}
public function getLatitudeNord() {
return $this->latitudeNord;
}
public function getLongitudeOuest() {
return $this->longitudeOuest;
}
public function getLatitudeSud() {
return $this->latitudeSud;
}
public function getLongitudeEst() {
return $this->longitudeEst;
}
public function getIndexLatitude() {
return $this->indexLatitude;
}
public function getIndexLongitude() {
return $this->indexLongitude;
}
public function getStations() {
return $this->stations;
}
public function getNombreStations() {
return count($this->stations);
}
public function getObservations() {
return $this->observations;
}
public function combinerMailles($maille, $sourceReference) {
if (is_array($maille['stations'])) {
foreach ($maille['stations'] as $source => $nombreStations) {
if (!array_key_exists($source, $this->stations)) {
$this->stations[$source] = $nombreStations;
$this->observations[$source] = $maille['observations'][$source];
} else {
$this->stations[$source] += $nombreStations;
$this->observations[$source] += $maille['observations'][$source];
}
}
} else {
if (!array_key_exists($sourceReference, $this->stations)) {
$this->stations[$sourceReference] = $maille['stations'];
$this->observations[$sourceReference] = $maille['observations'];
} else {
$this->stations[$sourceReference] += $maille['stations'];
$this->observations[$sourceReference] += $maille['observations'];
}
}
}
}
 
?>
/trunk/services/bibliotheque/EnteteHttp.php
New file
0,0 → 1,7
<?php
class EnteteHttp {
public $code = RestServeur::HTTP_CODE_OK;
public $encodage = 'utf-8';
public $mime = 'application/json';
}
?>
/trunk/services/bibliotheque/FormateurWfs.php
New file
0,0 → 1,124
<?php
 
class FormateurWfs {
const TYPE_MIME = 'text/xml';
private $bbox = null;
public function formaterGetCapabilities() {
$nomFichierWfs = dirname(__FILE__).DS."squelettes".DS."GetCapabilities.tpl.xml";
return SquelettePhp::analyser($nomFichierWfs);
}
public function formaterDescribeFeatureType($sources) {
$nomFichierWfs = dirname(__FILE__).DS."squelettes".DS."DescribeFeatureType.tpl.xml";
if (is_null($sources)) {
$sources = Config::get('sources_dispo');
}
$listeSources = is_array($sources) == 1 ? $sources : explode(',', $sources);
$item = array('listeSources' => $listeSources);
return SquelettePhp::analyser($nomFichierWfs, $item);
}
public function formaterGetFeature(& $stations, $sources) {
$nomFichierWfs = dirname(__FILE__).DS."squelettes".DS."GetFeature.tpl.xml";
$this->bbox = array('ouest' => null, 'est' => null, 'sud' => null, 'nord'=> null);
$stationsRetour = $this->mettreEnPageStations($stations);
$listeSources = implode(',', $sources);
$item = array('enveloppe' => $this->bbox, 'stations' => $stationsRetour, 'listeSources' => $listeSources);
return SquelettePhp::analyser($nomFichierWfs, $item);
}
private function mettreEnPageStations(& $stations) {
$station = array('longitude' => null, 'latitude' => null);
$stationsRetour = array();
foreach ($stations as $stationBdd) {
if ($this->estNonNul($stationBdd['longitude']) && $this->estNonNul($stationBdd['latitude'])
&& ($stationBdd['longitude'] != $station['longitude'] || $stationBdd['latitude'] != $station['latitude'])) {
if (isset($station['source'])) {
if ($station['source'] == 'floradata') {
$this->mettreEnPageStationFloradata($station);
} else {
$this->mettreEnPageStationMoissonnage($station);
}
$stationsRetour[] = $station;
}
foreach ($stationBdd as $cle => $valeur) {
if ($cle != 'taxon' && $cle != 'auteur') {
$station[$cle] = $valeur;
}
}
$station['taxons'] = array(trim($stationBdd['taxon']));
$station['auteurs'] = array(trim($stationBdd['auteur']));
$this->mettreAJourBbox($station);
} else {
$station['taxons'][] = trim($stationBdd['taxon']);
$station['auteurs'][] = trim($stationBdd['auteur']);
}
}
return $stationsRetour;
}
private function estNonNul($valeur) {
return (!is_null($valeur) && strlen(trim($valeur)) > 0);
}
private function mettreAJourBbox($station) {
if (is_null($this->bbox['sud']) || floatval($station['latitude']) < floatval($this->bbox['sud'])) {
$this->bbox['sud'] = $station['latitude'];
} elseif (is_null($this->bbox['nord']) || floatval($station['latitude']) > floatval($this->bbox['nord'])) {
$this->bbox['nord'] = $station['latitude'];
}
if (is_null($this->bbox['ouest']) || floatval($station['longitude']) < floatval($this->bbox['ouest'])) {
$this->bbox['ouest'] = $station['longitude'];
} elseif (is_null($this->bbox['est']) || floatval($station['longitude']) > floatval($this->bbox['est'])) {
$this->bbox['est'] = $station['longitude'];
}
}
private function mettreEnPageStationFloradata(& $station) {
$station['nom_station'] = trim($station['station']);
if ($this->estNonNul($station['zone_geo'])) {
$station['nom_station'] .= ", ".$station['zone_geo'];
}
$station['nom_station'] = str_replace("&", "&amp;", trim($station['nom_station']));
$station['departement'] = '';
$station['code_insee'] = '';
if ($this->estNonNul($station['ce_zone_geo'])) {
$station['code_insee'] = substr($station['ce_zone_geo'], 8);
$station['departement'] = substr($station['code_insee'],0, 2);
if (intval($station['departement']) > 95) {
$station['departement'] = substr($station['code_insee'],0, 2);
}
}
unset($station['station']);
unset($station['zone_geo']);
unset($station['ce_zone_geo']);
$station['taxons'] = str_replace("&", "&amp;", implode(', ', $station['taxons']));
$station['auteurs'] = str_replace("&", "&amp;", implode(', ', array_unique($station['auteurs'])));
}
private function mettreEnPageStationMoissonnage(& $station) {
$station['nom_station'] = str_replace("&", "&amp;", trim($station['nom']));
$station['departement'] = '';
if ($this->estNonNul($station['code_insee'])) {
$station['departement'] = substr($station['code_insee'],0, 2);
if (intval($station['departement']) > 95) {
$station['departement'] = substr($station['code_insee'],0, 2);
}
}
unset($station['nom']);
$station['taxons'] = str_replace("&", "&amp;", implode(', ', $station['taxons']));
$station['auteurs'] = str_replace("&", "&amp;", implode(', ', array_unique($station['auteurs'])));
}
public function formaterException(Exception $erreur) {
$nomFichierWfs = dirname(__FILE__).DS."squelettes".DS."Exception.tpl.xml";
$item = array('message' => $erreur->getMessage());
return SquelettePhp::analyser($nomFichierWfs, $item);
}
}
 
?>
/trunk/services/bibliotheque/Referentiel.php
New file
0,0 → 1,155
<?php
 
 
/**
* Classe qui va effectuer toutes les operations liees aux referentiels ou rechercher
* des informations sur les taxons dans les tables des referentiels dans la base de donnees
*
* Operations a utiliser :
* - recupererListeReferentielsDisponibles (statique) : recherche dans les fichiers de configuration
* la liste des referentiels disponibles et les renvoie dans un tableau
*
* - chargerTaxon : recherche dans la table possedant le meme nom que le nom du referentiel en attribut
* les informations generales sur un taxon (numero nomenclatural retenu, numero taxonomique,
* nom scientifique, rang) a partir de son numero taxonomique
* On stockera dans un attribut un tableau associatif contenant ces informations + le nom du referentiel,
* ou la valeur nulle si aucun taxon n'a ete trouve
*
* - recupererSousTaxons : a partir du numero nomenclatural d'un taxon, la fonction va recuperer
* tous les taxons de rang inferieur de maniere recursive jusqu'en ne plus en trouver de nouveaux
* la recherche s'effectuera seulement au niveau des rangs famille, genre, espece et sous-espece
* pour limiter le nombre d'informations qui sera a la fin renvoye
*
* - obtenirNumeroNomenclatural : recherche le numero nomenclatural d'un taxon a partir de son nom scientifique
*
* @package framework-0.3
* @author Alexandre GALIBERT <alexandre.galibert@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 2013 Tela Botanica (accueil@tela-botanica.org)
*
*/
 
 
 
class Referentiel {
private $nomComplet;
private $nomCourt;
private $taxon;
private $bdd = null;
private $nomsChampsBdtfx = array('nn' => 'num_nom_retenu', 'nt' => 'num_taxonomique', 'ns' => 'nom_sci');
private $nomsChampsBdtxa = array('nn' => 'num_nom_retenu', 'nt' => 'num_tax', 'ns' => 'nom_sci');
private $champs;
public function __construct($nomReferentiel, $taxon = null) {
$this->nomComplet = $nomReferentiel;
$this->nomCourt = current(explode('_', $nomReferentiel));
$proprieteChamps = 'nomsChamps' . ucfirst($this->nomCourt);
foreach ($this->$proprieteChamps as $nomCourt => $nomChamp) {
$this->champs[$nomCourt] = $nomChamp;
}
$this->taxon = $taxon;
}
public function renvoyerNomCompletReferentiel() {
return $this->nomComplet;
}
public function renvoyerTaxon() {
return $this->taxon;
}
public function chargerTaxon($typeNumero, $numTaxon) {
$taxon = null;
// verifier que le numero de taxon soit bien une chaine de caracteres composee uniquement
// que de nombres entiers avant de construire la requete SQL a executer
if (preg_match('/^\d+$/', $numTaxon) == 1) {
$champWhere = $typeNumero == 'nt' ? $this->champs['nt']: 'num_nom';
$requete =
"SELECT ".$this->champs['nn']." AS nn, ".$this->champs['nt']." AS nt, ".
$this->champs['ns']." AS nom, rang FROM ".$this->nomComplet." WHERE ".
$champWhere."={$numTaxon} AND num_nom=".$this->champs['nn']." ".
"ORDER BY rang, If(num_nom=".$this->champs['nn'].", 0, 1) LIMIT 0, 1";
$taxon = $this->getBdd()->recuperer($requete);
if ($taxon == false) {
$taxon = null;
} else {
$taxon['referentiel'] = $this->nomComplet;
}
}
$this->taxon = $taxon;
}
private function getBdd() {
if (is_null($this->bdd)) {
$this->bdd = new Bdd();
}
$nomBdd = Config::get('bdd_nom');
$this->bdd->requeter("USE ".$nomBdd);
return $this->bdd;
}
public function recupererSynonymesEtSousEspeces() {
$sousTaxons = array();
if (!is_null($this->taxon) && $this->taxon['rang'] >= Config::get('rang.espece')) {
$requete =
"SELECT ".$this->champs['nn']." AS nn, ".$this->champs['nt']." AS nt, ".
$this->champs['ns']." AS nom, rang FROM ".$this->nomComplet. " WHERE ".
$this->champs['nt']."=".$this->taxon['nt']." OR hierarchie LIKE '%-".$this->champs['nn']."-%'";
$sousTaxons = $this->getBdd()->recupererTous($requete);
}
return $sousTaxons;
}
public function recupererGenres() {
$sousTaxons = array();
if (!is_null($this->taxon) && $this->taxon['rang'] == Config::get('rang.famille')) {
$requete =
"SELECT ".$this->champs['nn']." AS nn, ".$this->champs['nt']." AS nt, ".
$this->champs['ns']." AS nom, rang FROM ".$this->nomComplet. " WHERE ".
"num_tax_sup=".$this->taxon['nn']." AND num_nom=".$this->champs['nn'];
$sousTaxons = $this->getBdd()->recupererTous($requete);
}
return $sousTaxons;
}
public static function recupererListeReferentielsDisponibles() {
$tableau = array();
$tableauPartiel = explode(',', Config::get('referentiels_dispo'));
$tableauPartiel = array_map('trim', $tableauPartiel);
foreach ($tableauPartiel as $champ) {
if (strpos($champ, '=') === false) {
$tableau[] = $champ;
} else {
list($cle, $val) = explode('=', $champ);
$clePropre = trim($cle);
$valeurPropre = trim($val);
$tableau[$clePropre] = $valeurPropre;
}
}
return $tableau;
}
public function obtenirNumeroNomenclatural($nomScientifique, $numeroNomenclatural = null) {
$aProteger = $this->getBdd()->proteger(trim($nomScientifique) . '%');
$requete = "SELECT ".$this->champs['nn']." AS nn FROM ".$this->nomComplet." ".
"WHERE ".$this->champs['ns']." LIKE ".$aProteger;
if (!is_null($numeroNomenclatural) || strlen($numeroNomenclatural) > 0) {
$requete .= " OR ".$this->champs['nn']."={$numeroNomenclatural}";
}
$taxon = $this->getBdd()->recuperer($requete);
if ($taxon == false) {
$taxon = null;
} else {
$taxon['referentiel'] = $this->nomComplet;
}
return $taxon;
}
}
 
?>
/trunk/services/bibliotheque/ResultatService.php
New file
0,0 → 1,9
<?php
 
class ResultatService {
public $mime = 'application/json';
public $encodage = 'utf-8';
public $corps = '';
}
 
?>
/trunk/services/index.php
New file
0,0 → 1,43
<?php
// Encodage : UTF-8
// Permet d'afficher le temps d'execution du service
$temps_debut = (isset($_GET['chrono']) && $_GET['chrono'] == 1) ? microtime(true) : '';
// +-------------------------------------------------------------------------------------------------------------------+
/**
* Serveur
*
* Description : initialise le chargement et l'exécution des services web.
*
//Auteur original :
* @author auteur <aut@tela-botanica.org>
* @copyright Tela-Botanica 1999-2008
* @licence GPL v3 & CeCILL v2
* @version $Id$
*/
// +-------------------------------------------------------------------------------------------------------------------+
 
// Le fichier autoload.inc.php du Framework de Tela Botanica doit être appelée avant tout autre chose dans l'application.
// Sinon, rien ne sera chargé.
// Chemin du fichier chargeant le framework requis
$framework = dirname(__FILE__).DIRECTORY_SEPARATOR.'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'));
// Initialisation et lancement du serveur
$Serveur = new RestServeur();
$Serveur->executer();
// Affiche le temps d'execution du service
if (isset($_GET['chrono']) && $_GET['chrono'] == 1) {
$temps_fin = microtime(true);
echo 'Temps d\'execution : '.round($temps_fin - $temps_debut, 4);
}
}
?>
/trunk/services/framework.php
New file
0,0 → 1,6
<?php
// Inclusion du Framework
// Renomer ce fichier en "framework.php"
// Indiquer ci-dessous le chemin absolu vers le fichier autoload.inc.php de la bonne version du Framework
require_once '/home/alex/web/framework-0.3/framework/Framework.php';
?>
/trunk/services
New file
Property changes:
Added: svn:ignore
+.htaccess
/trunk/widget/bibliotheque/WidgetCommun.php
New file
0,0 → 1,431
<?php
abstract class WidgetCommun {
protected $config = null;
protected $parametres = null;
protected $messages = array();
protected $debug = array();
public function __construct($config, $parametres) {
$this->config = $config;
$this->parserFichierIni($config['chemins']['widgetCourantDossier'].'config.ini');
$this->parametres = $parametres;
}
/**
* Parse le fichier ini donné en paramètre
* @param string $fichier_ini nom du fichier ini à parser
* @return boolean true si le fichier ini a été trouvé.
*/
private function parserFichierIni($fichier_ini) {
$retour = false;
if (file_exists($fichier_ini)) {
$ini = parse_ini_file($fichier_ini, true);
$this->fusionner($ini);
$retour = true;
}
return $retour;
}
 
/**
* fusionne un tableau de paramètres avec le tableau de config global
* @param array $ini le tableau à fusionner
*/
private function fusionner(array $ini) {
$this->config = array_merge($this->config, $ini);
}
protected function traiterNomMethodeExecuter($nom) {
$methode = 'executer';
$methode .= str_replace(' ', '', ucwords(str_replace('-', ' ', strtolower($nom))));
return $methode;
}
//+----------------------------------------------------------------------------------------------------------------+
// GESTION des CLASSES CHARGÉES à la DEMANDE
protected function getDao() {
if (! isset($this->dao)) {
$this->dao = new Dao();
}
return $this->dao;
}
//+----------------------------------------------------------------------------------------------------------------+
// GESTION DE MÉTHODES COMMUNES ENTRE LES SERVICES
protected function getUrlImage($id, $format = 'L') {
$url_tpl = $this->config['chemins']['celImgUrlTpl'];
$id = sprintf('%09s', $id).$format;
$url = sprintf($url_tpl, $id);
return $url;
}
protected function encoderMotCle($mot_cle) {
return md5(mb_strtolower($mot_cle));
}
private function protegerMotsCles($mots_cles, $type) {
$separateur = ($type == self::TYPE_IMG) ? ',' : ';' ;
$mots_cles_a_proteger = explode($separateur,rtrim(trim($mots_cles), $separateur));
foreach ($mots_cles_a_proteger as $mot) {
$mots_cles_proteges[] = $this->bdd->quote($mot);
}
$mots_cles = implode(',', $mots_cles_proteges);
return $mots_cles;
}
protected function tronquerCourriel($courriel) {
$courriel = preg_replace('/[^@]+$/i', '...', $courriel);
return $courriel;
}
protected function nettoyerTableau($tableau) {
foreach ($tableau as $cle => $valeur) {
if (is_array($valeur)) {
$valeur = $this->nettoyerTableau($valeur);
} else {
$valeur = $this->nettoyerTexte($valeur);
}
$tableau[$cle] = $valeur;
}
return $tableau;
}
protected function nettoyerTexte($txt) {
$txt = preg_replace('/&(?!([a-z]+|#[0-9]+|#x[0-9][a-f]+);)/i', '&amp;', $txt);
$txt = preg_replace('/^(?:000null|null)$/i', '', $txt);
return $txt;
}
protected function etreVide($valeur) {
$vide = false;
if ($valeur == '' || $valeur == 'null'|| $valeur == '000null' || $valeur == '0') {
$vide = true;
}
return $vide;
}
protected function formaterDate($date_heure_mysql, $format = '%A %d %B %Y à %H:%M') {
$date_formatee = '';
if (!$this->etreVide($date_heure_mysql)) {
$timestamp = $this->convertirDateHeureMysqlEnTimestamp($date_heure_mysql);
$date_formatee = strftime($format, $timestamp);
}
return $date_formatee;
}
 
protected function convertirDateHeureMysqlEnTimestamp($date_heure_mysql){
$val = explode(' ', $date_heure_mysql);
$date = explode('-', $val[0]);
$heure = explode(':', $val[1]);
return mktime((int) $heure[0], (int) $heure[1], (int) $heure[2], (int) $date[1], (int) $date[2], (int) $date[0]);
}
//+----------------------------------------------------------------------------------------------------------------+
// GESTION DE L'IDENTIFICATION et des UTILISATEURS
protected function getAuthIdentifiant() {
$id = (isset($_SERVER['PHP_AUTH_USER'])) ? $_SERVER['PHP_AUTH_USER'] : null;
return $id;
}
protected function getAuthMotDePasse() {
$mdp = (isset($_SERVER['PHP_AUTH_PW'])) ? $_SERVER['PHP_AUTH_PW'] : null;
return $mdp;
}
protected function authentifierAdmin() {
$message_accueil = "Veuillez vous identifier avec votre compte Tela Botanica.";
$message_echec = "Accès limité aux administrateurs du CEL.\n".
"Votre tentative d'identification a échoué.\n".
"Actualiser la page pour essayer à nouveau si vous êtes bien inscrit comme administrateur.";
return $this->authentifier($message_accueil, $message_echec, 'Admin');
}
protected function authentifierUtilisateur() {
$message_accueil = "Veuillez vous identifier avec votre compte Tela Botanica.";
$message_echec = "Accès limité aux utilisateur du CEL.\n".
"Inscrivez vous http://www.tela-botanica.org/page:inscription pour le devenir.\n".
"Votre tentative d'identification a échoué.\n".
"Actualiser la page pour essayer à nouveau si vous êtes déjà inscrit ou contacter 'accueil@tela-botanica.org'.";
return $this->authentifier($message_accueil, $message_echec, 'Utilisateur');
}
private function authentifier($message_accueil, $message_echec, $type) {
$id = $this->getAuthIdentifiant();
if (!isset($id)) {
$this->envoyerAuth($message_accueil, $message_echec);
} else {
if ($type == 'Utilisateur' && $this->getAuthMotDePasse() == 'debug') {
$autorisation = true;
} else {
$methodeAutorisation = "etre{$type}Autorise";
$autorisation = $this->$methodeAutorisation();
}
if ($autorisation == false) {
$this->envoyerAuth($message_accueil, $message_echec);
}
}
return true;
}
protected function etreUtilisateurAutorise() {
$identifiant = $this->getAuthIdentifiant();
$mdp = md5($this->getAuthMotDePasse());
$url = sprintf($this->config['authentification']['serviceUrlTpl'], $identifiant, $mdp);
$json = $this->getDao()->consulter($url);
$existe = json_decode($json);
$autorisation = (isset($existe) && $existe) ? true :false;
return $autorisation;
}
protected function etreAdminAutorise($identifiant) {
$identifiant = $this->getAuthIdentifiant();
$autorisation = ($this->etreUtilisateurAutorise() && $this->etreAdminCel($identifiant)) ? true : false;
return $autorisation;
}
protected function etreAdminCel($courriel) {
$admins = $this->config['authentification']['administrateurs'];
$courriels_autorises = explode(',', $admins);
 
$autorisation = (in_array($courriel, $courriels_autorises)) ? true : false ;
return $autorisation;
}
/**
* Prend en paramêtre un tableau de courriels et retourne après avoir intérogé un service we de l'annuaire
* une tableau avec en clé le courriel et en valeur, un tableau associatif :
* - nom : le nom de l'utilisateur
* - prenom : le prénom de l'utilisateur.
* @param array $courriels un tableau de courriels pour lesquels il faut recherche le prénom et nom.
*/
protected function recupererUtilisateursNomPrenom(Array $courriels) {
// Récupération des données au format Json
$service = "utilisateur/prenom-nom-par-courriel/".implode(',', $courriels);
$url = sprintf($this->config['chemins']['baseURLServicesAnnuaireTpl'], $service);
$json = $this->getDao()->consulter($url);
return (array) json_decode($json);
}
protected function recupererUtilisateursIdentite(Array $courriels) {
// Récupération des données au format Json
$service = "utilisateur/identite-par-courriel/".implode(',', $courriels);
$url = sprintf($this->config['chemins']['baseURLServicesAnnuaireTpl'], $service);
$json = $this->getDao()->consulter($url);
$utilisateurs = json_decode($json);
foreach ($courriels as $courriel) {
$info = array('id' => null, 'intitule' => '');
if (isset($utilisateurs->$courriel)) {
$info['intitule'] = $utilisateurs->$courriel->intitule;
$info['id'] = $utilisateurs->$courriel->id;
} else {
$info['intitule'] = $this->tronquerCourriel($courriel);
}
$noms[$courriel] = $info;
}
return $noms;
}
//+----------------------------------------------------------------------------------------------------------------+
// GESTION de l'ENVOIE au NAVIGATEUR
 
protected function envoyerJsonp($donnees = null, $encodage = 'utf-8') {
$contenu = $_GET['callback'].'('.json_encode($donnees).');';
$this->envoyer($contenu, 'text/html', $encodage);
}
protected function envoyer($donnees = null, $mime = 'text/html', $encodage = 'utf-8') {
// Traitements des messages d'erreurs et données
if (count($this->messages) != 0) {
header('HTTP/1.1 500 Internal Server Error');
$mime = 'text/html';
$encodage = 'utf-8';
$sortie = '<html>'.
'<head><title>Messages</title></head>'.
'<body><pre>'.implode("\n", $this->messages).'</pre><body>'.
'</html>';
} else {
$sortie = $donnees;
if (is_null($donnees)) {
$sortie = 'OK';
}
}
 
// Gestion de l'envoie du déboguage
$this->envoyerDebogage();
 
// Envoie sur la sortie standard
$this->envoyerContenu($encodage, $mime, $sortie);
}
 
private function envoyerDebogage() {
if (!is_array($this->debug)) {
$this->debug[] = $this->debug;
}
if (count($this->debug) != 0) {
foreach ($this->debug as $cle => $val) {
if (is_array($val)) {
$this->debug[$cle] = print_r($val, true);
}
}
header('X-DebugJrest-Data:'.json_encode($this->debug));
}
}
 
private function envoyerContenu($encodage, $mime, $contenu) {
if (!is_null($mime) && !is_null($encodage)) {
header("Content-Type: $mime; charset=$encodage");
} else if (!is_null($mime) && is_null($encodage)) {
header("Content-Type: $mime");
}
print_r($contenu);
}
private function envoyerAuth($message_accueil, $message_echec) {
header('HTTP/1.0 401 Unauthorized');
header('WWW-Authenticate: Basic realm="'.mb_convert_encoding($message_accueil, 'ISO-8859-1', 'UTF-8').'"');
header('Content-type: text/plain; charset=UTF-8');
print $message_echec;
exit(0);
}
//+----------------------------------------------------------------------------------------------------------------+
// GESTION DES SQUELETTES (PHP, TXT...)
/**
* Méthode prenant en paramètre un tableau associatif, les clés seront recherchées dans le texte pour être
* remplacer par la valeur. Dans le texte, les clés devront être entre accolades : {}
*
* @param String $txt le texte où chercher les motifs.
* @param Array $donnees un tableau associatif contenant les motifs à remplacer.
*
* @return String le texte avec les motifs remplacer par les valeurs du tableau.
*/
protected static function traiterSqueletteTxt($txt, Array $donnees = array()) {
$motifs = array();
$valeurs = array();
foreach ($donnees as $cle => $valeur) {
if (strpos($cle, '{') === false && strpos($cle, '}') === false) {
$motifs = '{'.$cle.'}';
$valeurs = $valeur;
}
}
$txt = str_replace($motifs, $valeurs, $txt);
return $txt;
}
 
/**
* Méthode prenant en paramètre un chemin de fichier squelette et un tableau associatif de données,
* en extrait les variables, charge le squelette et retourne le résultat des deux combinés.
*
* @param String $fichier le chemin du fichier du squelette
* @param Array $donnees un tableau associatif contenant les variables a injecter dans le squelette.
*
* @return boolean false si le squelette n'existe pas, sinon la chaine résultat.
*/
protected static function traiterSquelettePhp($fichier, Array $donnees = array()) {
$sortie = false;
if (file_exists($fichier)) {
// Extraction des variables du tableau de données
extract($donnees);
// Démarage de la bufferisation de sortie
ob_start();
// Si les tags courts sont activés
if ((bool) @ini_get('short_open_tag') === true) {
// Simple inclusion du squelette
include $fichier;
} else {
// Sinon, remplacement des tags courts par la syntaxe classique avec echo
$html_et_code_php = self::traiterTagsCourts($fichier);
// Pour évaluer du php mélangé dans du html il est nécessaire de fermer la balise php ouverte par eval
$html_et_code_php = '?>'.$html_et_code_php;
// Interprétation du html et du php dans le buffer
echo eval($html_et_code_php);
}
// Récupèration du contenu du buffer
$sortie = ob_get_contents();
// Suppression du buffer
@ob_end_clean();
} else {
$msg = "Le fichier du squelette '$fichier' n'existe pas.";
trigger_error($msg, E_USER_WARNING);
}
// Retourne le contenu
return $sortie;
}
 
/**
* Fonction chargeant le contenu du squelette et remplaçant les tags court php (<?= ...) par un tag long avec echo.
*
* @param String $chemin_squelette le chemin du fichier du squelette
*
* @return string le contenu du fichier du squelette php avec les tags courts remplacés.
*/
private static function traiterTagsCourts($chemin_squelette) {
$contenu = file_get_contents($chemin_squelette);
// Remplacement de tags courts par un tag long avec echo
$contenu = str_replace('<?=', '<?php echo ', $contenu);
// Ajout systématique d'un point virgule avant la fermeture php
$contenu = preg_replace("/;*\s*\?>/", "; ?>", $contenu);
return $contenu;
}
//+----------------------------------------------------------------------------------------------------------------+
// UTILITAIRES
/**
* Permet de trier un tableau multi-dimenssionnel en gardant l'ordre des clés.
*
* @param Array $array le tableau à trier
* @param Array $cols tableau indiquant en clé la colonne à trier et en valeur l'ordre avec SORT_ASC ou SORT_DESC
* @author cagret at gmail dot com
* @see http://fr.php.net/manual/fr/function.array-multisort.php Post du 21-Jun-2009 12:38
*/
public static function trierTableauMd($array, $cols) {
$colarr = array();
foreach ($cols as $col => $order) {
$colarr[$col] = array();
foreach ($array as $k => $row) {
$colarr[$col]['_'.$k] = strtolower(self::supprimerAccents($row[$col]));
}
}
$params = array();
foreach ($cols as $col => $order) {
$params[] =& $colarr[$col];
$params = array_merge($params, (array)$order);
}
call_user_func_array('array_multisort', $params);
$ret = array();
$keys = array();
$first = true;
foreach ($colarr as $col => $arr) {
foreach ($arr as $k => $v) {
if ($first) {
$keys[$k] = substr($k,1);
}
$k = $keys[$k];
if (!isset($ret[$k])) {
$ret[$k] = $array[$k];
}
$ret[$k][$col] = $array[$k][$col];
}
$first = false;
}
return $ret;
}
private static function supprimerAccents($str, $charset='utf-8')
{
$str = htmlentities($str, ENT_NOQUOTES, $charset);
$str = preg_replace('#&([A-za-z])(?:acute|cedil|circ|grave|orn|ring|slash|th|tilde|uml);#', '\1', $str);
$str = preg_replace('#&([A-za-z]{2})(?:lig);#', '\1', $str); // pour les ligatures e.g. '&oelig;'
$str = preg_replace('#&[^;]+;#', '', $str); // supprime les autres caractères
return $str;
}
}
?>
/trunk/widget/bibliotheque/Dao.php
New file
0,0 → 1,157
<?php
// declare(encoding='UTF-8');
/**
* Classe modèle spécifique à l'application, donc d'accés au données, elle ne devrait pas être appelée de l'extérieur.
*
* @category php5
* @package Widget
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright 2010 Tela-Botanica
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
* @license http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
* @version SVN: $Id$
*/
class Dao {
const HTTP_URL_REQUETE_SEPARATEUR = '&';
const HTTP_URL_REQUETE_CLE_VALEUR_SEPARATEUR = '=';
private $http_methodes = array('GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS', 'CONNECT', 'TRACE');
protected $parametres = null;
private $url = null;
private $reponse_entetes = null;
//+----------------------------------------------------------------------------------------------------------------+
// ACCESSEURS
public function getReponseEntetes($cle) {
return $this->reponse_entetes;
}
public function getParametre($cle) {
$valeur = (isset($this->parametres[$cle])) ? $this->parametres[$cle] : null;
return $valeur;
}
public function ajouterParametre($cle, $valeur) {
$this->parametres[$cle] = $valeur;
}
public function supprimerParametre($cle) {
unset($this->parametres[$cle]);
}
public function nettoyerParametres() {
$this->parametres = null;
}
//+----------------------------------------------------------------------------------------------------------------+
// MÉTHODES
public function consulter($url) {
$retour = $this->envoyerRequete($url, 'GET');
return $retour;
}
public function ajouter($url, Array $donnees) {
$retour = $this->envoyerRequete($url, 'PUT', $donnees);
return $retour;
}
public function modifier($url, Array $donnees) {
$retour = $this->envoyerRequete($url, 'POST', $donnees);
return $retour;
}
public function supprimer($url) {
$retour = $this->envoyerRequete($url, 'DELETE');
return $retour;
}
public function envoyerRequete($url, $mode, Array $donnees = array()) {
$this->url = $url;
$contenu = false;
if (! in_array($mode, $this->http_methodes)) {
$e = "Le mode de requête '$mode' n'est pas accepté!";
trigger_error($e, E_USER_WARNING);
} else {
if ($mode == 'GET') {
$this->traiterUrlParametres();
}
$contexte = stream_context_create(array(
'http' => array(
'method' => $mode,
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'content' => http_build_query($donnees, null, self::HTTP_URL_REQUETE_SEPARATEUR))));
$flux = @fopen($this->url, 'r', false, $contexte);
if (!$flux) {
$this->reponse_entetes = $http_response_header;
$e = "L'ouverture de l'url '{$this->url}' par la méthode HTTP '$mode' a échoué!";
trigger_error($e, E_USER_WARNING);
} else {
// Informations sur les en-têtes et métadonnées du flux
$this->reponse_entetes = stream_get_meta_data($flux);
// Contenu actuel de $url
$contenu = stream_get_contents($flux);
fclose($flux);
}
$this->traiterEntete();
}
$this->reinitialiser();
return $contenu;
}
private function traiterUrlParametres() {
$parametres = array();
if (count($this->parametres) > 0) {
foreach ($this->parametres as $cle => $valeur) {
$cle = rawurlencode($cle);
$valeur = rawurlencode($valeur);
$parametres[] = $cle.self::HTTP_URL_REQUETE_CLE_VALEUR_SEPARATEUR.$valeur;
}
$url_parametres = implode(self::HTTP_URL_REQUETE_SEPARATEUR, $parametres);
$this->url = $this->url.'?'.$url_parametres;
}
}
private function traiterEntete() {
$infos = $this->analyserEntete();
$this->traiterEnteteDebogage($infos);
}
private function analyserEntete() {
$entetes = $this->reponse_entetes;
$infos = array('date' => null, 'uri' => $this->url, 'debogages' => null);
if (isset($entetes['wrapper_data'])) {
$entetes = $entetes['wrapper_data'];
}
foreach ($entetes as $entete) {
if (preg_match('/^X_REST_DEBOGAGE_MESSAGES: (.+)$/', $entete, $match)) {
$infos['debogages'] = json_decode($match[1]);
}
if (preg_match('/^Date: .+ ([012][0-9]:[012345][0-9]:[012345][0-9]) .*$/', $entete, $match)) {
$infos['date'] = $match[1];
}
}
return $infos;
}
private function traiterEnteteDebogage($entetes_analyses) {
if (isset($entetes['debogages'])) {
$date = $entetes['date'];
$uri = $entetes['uri'];
$debogages = $entetes['debogages'];
foreach ($debogages as $debogage) {
$e = "DEBOGAGE : $date - $uri :\n$debogage";
trigger_error($e, E_USER_NOTICE);
}
}
}
private function reinitialiser() {
$this->nettoyerParametres();
}
}
 
?>
/trunk/widget/index.php
New file
0,0 → 1,5
<?php
require 'Widget.php';
$widget = new Widget();
$widget->executer();
?>
/trunk/widget/widget.ini.defaut.php
New file
0,0 → 1,49
;<?/*
[parametres]
;Memoire maxi pour les services : 128Mo = 134217728 ; 256Mo = 268435456 ; 512Mo = 536870912 ; 1Go = 1073741824
limiteMemoire = "512M"
; Niveau d'erreur PHP
erreurNiveau = 30719 ; E_ALL = 30719
; Séparateur d'url en entrée
argSeparatorInput = "&"
; Indication de la locale (setLocale(LC_ALL, ?)) pour les classes appelées par Widget.php
locale = "fr_FR.UTF-8"
; Indication du fuseau horraire par défaut date_default_timezone_set(?)pour les classes appelées par Widget.php
fuseauHoraire = "Europe/Paris"
 
[chemins]
; Chemins à utiliser dans la méthode autoload des widgets
autoload = "bibliotheque/"
; Dossier contenant les widgets
widgetsDossier = "modules/"
; Dossier contenant le widget demandé construit dynamiquement dans le fichier Widget.php
widgetCourantDossier = ""
; Dossier contenant les fichiers des bibliothèques tierces
bibliothequeDossier = "bibliotheque/"
; Base de l'url servant à appeler les widgets
baseURL = "/moissonnage/widget/"
; URL de base absolue des Widgets du CEL construit dynamiquement dans le fichier WidgetCommun.php
baseURLAbsoluDyn = ""
; URL des services web du CEL sous forme de template à utiliser avec sprintf
baseURLServicesCelTpl = "http://www.tela-botanica.org/service:cel:%s"
; URL des services web du CEL sous forme de template à utiliser avec sprintf
baseURLServicesAnnuaireTpl = "http://www.tela-botanica.org/service:annuaire:%s"
; Squelette d'Url permettant d'afficher une image du CEL (remplace %s par l'id de l'image sans underscore)
celImgUrlTpl = "http://www.tela-botanica.org/appli:cel-img:%s.jpg"
; Squelette d'URL pour les services web d'eFlore.
baseURLServicesEfloreTpl = "http://www.tela-botanica.org/service:eflore:%s/%s/%s"
; Squelette d'URL pour les services web a tester en local.
baseURLServicesTpl = "http://localhost/moissonnage/services/0.1%s"
; Dossier de stockage temporaire des images (ATTENTION : mettre le slash à la fin)
imagesTempDossier = "/home/telabotap/www/eflore/cel/cache/images/"
; Squelette d'URL pour les images temporaires sotckées sur le serveur
imagesTempUrlTpl = "http://www.tela-botanica.org/eflore/cel/cache/images/%s"
; Url du service fournissant des infos sur les noms à partir d'un num tax
infosTaxonUrl = "http://www.tela-botanica.org/service:eflore:0.1/bdtfx/noms/%s"
; Url du service wiki fournissant les pages d'aide
aideWikiniUrl = 'http://www.tela-botanica.org/wikini/eflore/api/rest/0.5/pages/{page}?txt.format=text/html';
 
[authentification]
serviceUrlTpl = "http://www.tela-botanica.org/service:annuaire:TestLoginMdp/%s/%s"
administrateurs = aurelien@tela-botanica.org,david.delon@clapas.net,jpm@tela-botanica.org,marie@tela-botanica.org
;*/?>
/trunk/widget/modules/carto/config.defaut.ini
New file
0,0 → 1,19
[carto]
 
communeImageUrl = "http://www.tela-botanica.org/commun/icones/carto/commune.png"
pointImageUrl = "http://www.tela-botanica.org/commun/icones/carto/point2.png"
clusterImageUrl = "http://www.tela-botanica.org/commun/icones/carto/cluster.png"
sourcesDispo = "floradata,sophy"
sourceParDefaut = "floradata"
liensVersSources = "http://www.tela-botanica.org/page:cel,http://sophy.u-3mrs.fr/"
nomSourcesDispo = "Observations Flora Data,Données Sophy"
titreLegende = "Nombre Stations par maille"
 
; Chemin vers le dossier contenant les fichiers kmz des limites communales
communesKmzChemin = "/home/telabotap/www/carto/kml/communes/,/home/telabotap/www/carto/kml/communes_incompletes/"
; Template de l'url où charger les fichiers kml des limites communales.
limitesCommunaleUrlTpl = "http://www.tela-botanica.org/carto/kml/%s/%s"
 
;parametres lies a l'affichage des donnees sur la carte
zoomMaximumMaillage = 13
seuilMaillage = 250
/trunk/widget/modules/carto/Carto.php
New file
0,0 → 1,174
<?php
 
class Carto extends WidgetCommun {
const SERVICE_CARTO_NOM = 'carto';
const SERVICE_CARTO_ACTION_DEFAUT = 'carto';
private $carte = null;
private $source = null;
private $titre = null;
private $logo = null;
private $urlSite = null;
private $numeroNomenclatural = '*';
private $numeroTaxon = '*';
private $referentiel = '*';
private $departement = '*';
private $auteur = '*';
private $dateDebut = '*';
private $dateFin = '*';
private $nbJours = 0;
/**
* Methode appelee par defaut pour executer ce widget
*/
public function executer() {
$retour = null;
// recuperer les parametres de l'URL
$this->extraireParametres();
// verifier la disponibilite des services et ressources demandees
$methode = $this->traiterNomMethodeExecuter($this->carte);
if (method_exists($this, $methode)) {
$retour = $this->$methode();
} else {
$this->messages[] = "Ce type de service '$methode' n'est pas disponible.";
}
if (is_null($retour)) {
$info = 'Un problème est survenu : '.print_r($this->messages, true);
$this->envoyer($info);
} else {
$squelette = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'squelettes' . DIRECTORY_SEPARATOR
. $retour['squelette'] . '.tpl.html';
$html = $this->traiterSquelettePhp($squelette, $retour['donnees']);
$this->envoyer($html);
}
}
public function extraireParametres() {
extract($this->parametres);
$this->carte = (isset($carte) ? $carte : self::SERVICE_CARTO_ACTION_DEFAUT);
$this->source = (isset($source) ? $source : $this->config['carto']['sourceParDefaut']);
$this->logo = (isset($logo) ? $logo : null);
$this->titre = (isset($titre) ? $titre : null);
$this->urlSite = (isset($url_site) ? $url_site : null);
$this->numeroTaxon = (isset($num_taxon) ? $num_taxon : '*');
$this->numeroNomenclatural = (isset($nn) ? $nn : '*');
$this->departement = (isset($dept) ? $dept : '*');
$this->referentiel = (isset($referentiel) ? $referentiel : '*');
$this->auteur = (isset($auteur) ? $auteur : '*');
$this->dateDebut = (isset($date_debut) ? $date_debut : '*');
$this->dateFin = (isset($date_fin) ? $date_fin : '*');
$this->nbJours = (isset($nb_jours) ? intval($nb_jours) : 0);
}
/**
* Carte par défaut
*/
public function executerCarto() {
$widget = null;
$url_base = sprintf($this->config['chemins']['baseURLAbsoluDyn'], '');
// Création des infos du widget
$widget['donnees']['url_serivce_carto'] = $this->contruireUrlServiceCarto();
$widget['donnees']['url_base'] = $url_base;
$widget['donnees']['source'] = $this->source;
$widget['donnees']['titre'] = $this->titre;
$widget['donnees']['logo'] = $this->logo;
$widget['donnees']['url_site'] = $this->urlSite;
$widget['donnees']['auteur'] = $this->auteur;
$widget['donnees']['nn'] = $this->numeroNomenclatural;
$widget['donnees']['num_taxon'] = $this->numeroTaxon;
$widget['donnees']['departement'] = $this->departement;
$widget['donnees']['referentiel'] = $this->referentiel;
$widget['donnees']['date_debut'] = $this->dateDebut;
$widget['donnees']['date_fin'] = $this->dateFin;
$widget['donnees']['nb_jours'] = $this->nbJours;
$widget['donnees']['communeImageUrl'] = $this->config['carto']['communeImageUrl'];
$widget['donnees']['pointImageUrl'] = $this->config['carto']['pointImageUrl'];
$widget['donnees']['clusterImageUrl'] = $this->config['carto']['clusterImageUrl'];
$widget['donnees']['liensVersSources'] = $this->config['carto']['liensVersSources'];
$widget['donnees']['listeSources'] = $this->config['carto']['sourcesDispo'];
$widget['donnees']['nomListeSources'] = $this->config['carto']['nomSourcesDispo'];
$widget['donnees']['titreLegende'] = $this->config['carto']['titreLegende'];
$widget['donnees']['urlLimitesCommunales'] = $this->obtenirUrlsLimitesCommunales();
$widget['donnees']['zoomMaximumMaillage'] = $this->config['carto']['zoomMaximumMaillage'];
$widget['donnees']['seuilMaillage'] = $this->config['carto']['seuilMaillage'];
$widget['squelette'] = 'carto';
return $widget;
}
private function contruireUrlServiceCarto($action = null) {
// Création url données json
$url = sprintf($this->config['chemins']['baseURLServicesTpl'], '');
if ($action) {
$url .= "/$action";
$parametres_retenus = array();
$parametres_a_tester = array('source', 'utilisateur', 'referentiel', 'dept', 'num_taxon');
foreach ($parametres_a_tester as $param) {
if (isset($this->$param) && $this->$param != '*') {
$parametres_retenus[$param] = $this->$param;
}
}
if (count($parametres_retenus) > 0) {
$parametres_url = array();
foreach ($parametres_retenus as $cle => $valeur) {
$parametres_url[] = $cle.'='.$valeur;
}
$url .= '?'.implode('&', $parametres_url);
}
}
return $url;
}
private function obtenirUrlsLimitesCommunales() {
$urls = null;
if (isset($this->departement)) {
// si on veut afficher les limites départementales on va compter et chercher les noms de fichiers
$fichiersKml = $this->chercherFichierKml();
if (count($fichiersKml) > 0) {
foreach ($fichiersKml as $kml => $dossier){
$url_limites_communales = sprintf($this->config['carto']['limitesCommunaleUrlTpl'], $dossier, $kml);
$urls[] = $url_limites_communales;
}
}
}
$urls = json_encode($urls);
return $urls;
}
private function chercherFichierKml(){
$fichiers = array();
$chemins = explode(',', $this->config['carto']['communesKmzChemin']);
$departements = explode(',', $this->departement);// plrs code de départements peuvent être demandés séparés par des virgules
$departements_trouves = array();
foreach ($chemins as $dossier_chemin) {
if ($dossier_ressource = opendir($dossier_chemin)) {
while ($element = readdir($dossier_ressource)) {
if ($element != '.' && $element != '..') {
foreach ($departements as $departement) {
$nom_dossier = basename($dossier_chemin);
if (!isset($departements_trouves[$departement]) || $departements_trouves[$departement] == $nom_dossier) {
$dept_protege = preg_quote($departement);
if (!is_dir($dossier_chemin.'/'.$element) && preg_match("/^$dept_protege(?:_[0-9]+|)\.kml$/", $element)) {
$fichiers[$element] = $nom_dossier;
$departements_trouves[$departement] = $nom_dossier;
}
}
}
}
}
closedir($dossier_ressource);
}
}
return $fichiers;
}
}
 
?>
/trunk/widget/modules/carto/squelettes/images/chargement.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/widget/modules/carto/squelettes/images/chargement.gif
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/widget/modules/carto/squelettes/images/fermeture.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/widget/modules/carto/squelettes/images/fermeture.png
New file
Property changes:
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/widget/modules/carto/squelettes/images/tri.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/widget/modules/carto/squelettes/images/tri.png
New file
Property changes:
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/widget/modules/carto/squelettes/images/ouverture.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/widget/modules/carto/squelettes/images/ouverture.png
New file
Property changes:
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/widget/modules/carto/squelettes/images/tri_croissant.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/widget/modules/carto/squelettes/images/tri_croissant.png
New file
Property changes:
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/widget/modules/carto/squelettes/images/information.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/widget/modules/carto/squelettes/images/information.png
New file
Property changes:
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/widget/modules/carto/squelettes/images/tri_decroissant.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
/trunk/widget/modules/carto/squelettes/images/tri_decroissant.png
New file
Property changes:
Added: svn:mime-type
+image/png
\ No newline at end of property
/trunk/widget/modules/carto/squelettes/scripts/L.KML.js
New file
0,0 → 1,393
/*
*
* Copyright (c) 2011-2012, Pavel Shramov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
 
// Adaptation Alexandre GALIBERT :
// - Define fill opacity for polygons at 0 for transparent rendering
// - Disable creation of icons for KML elements
// - Specific beahaviour to add an array of files by their urls. A variable will define
// the status of the processing (BUSY or READY) and managed with a counter for the number
// of files remaining to parse. Once all files parsed, the map zooms on KML spatial elements
 
const KML_READY = 0;
const KML_BUSY = 1;
 
 
L.KML = L.FeatureGroup.extend({
options: {
async: true
},
 
initialize: function(kml, options) {
L.Util.setOptions(this, options);
this._kml = kml;
this._status = KML_READY;
this._onWaiting = 0;
this._layers = {};
 
if (kml) {
this.addKML(kml, options, this.options.async);
}
},
 
loadXML: function(url, cb, options, async) {
if (async == undefined) async = this.options.async;
if (options == undefined) options = this.options;
 
var req = new window.XMLHttpRequest();
req.open('GET', url, async);
try {
req.overrideMimeType('text/xml'); // unsupported by IE
} catch(e) {}
req.onreadystatechange = function() {
if (req.readyState != 4) return;
if(req.status == 200) cb(req.responseXML, options);
};
req.send(null);
},
 
addKMLFiles: function(urlList, options, async) {
this._status = KML_BUSY;
this._onWaiting = urlList.length;
for (var index = 0; index < urlList.length; index ++) {
this.addKML(urlList[index], options, async);
}
},
addKML: function(url, options, async) {
var _this = this;
var cb = function(gpx, options) { _this._addKML(gpx, options) };
this.loadXML(url, cb, options, async);
},
 
_addKML: function(xml, options) {
var layers = L.KML.parseKML(xml);
if (!layers || !layers.length) return;
for (var i = 0; i < layers.length; i++)
{
this.fire('addlayer', {
layer: layers[i]
});
this.addLayer(layers[i]);
}
this.latLngs = L.KML.getLatLngs(xml);
this.fire("loaded");
this._onWaiting --;
if (this._onWaiting == 0) {
this._status = KML_READY;
this._map.fitBounds(this.getBounds());
}
},
getStatus: function() {
return this._status;
},
 
latLngs: []
});
 
L.Util.extend(L.KML, {
 
parseKML: function (xml) {
var style = this.parseStyle(xml);
var el = xml.getElementsByTagName("Folder");
var layers = [], l;
for (var i = 0; i < el.length; i++) {
if (!this._check_folder(el[i])) { continue; }
l = this.parseFolder(el[i], style);
if (l) { layers.push(l); }
}
el = xml.getElementsByTagName('Placemark');
for (var j = 0; j < el.length; j++) {
if (!this._check_folder(el[j])) { continue; }
l = this.parsePlacemark(el[j], xml, style);
if (l) { layers.push(l); }
}
return layers;
},
 
// Return false if e's first parent Folder is not [folder]
// - returns true if no parent Folders
_check_folder: function (e, folder) {
e = e.parentElement;
while (e && e.tagName !== "Folder")
{
e = e.parentElement;
}
return !e || e === folder;
},
 
parseStyle: function (xml) {
var style = {};
var sl = xml.getElementsByTagName("Style");
 
//for (var i = 0; i < sl.length; i++) {
var attributes = {color: true, width: true, Icon: true, href: true,
hotSpot: true};
 
function _parse(xml) {
var options = {};
for (var i = 0; i < xml.childNodes.length; i++) {
var e = xml.childNodes[i];
var key = e.tagName;
if (!attributes[key]) { continue; }
if (key === 'hotSpot')
{
for (var j = 0; j < e.attributes.length; j++) {
options[e.attributes[j].name] = e.attributes[j].nodeValue;
}
} else {
var value = e.childNodes[0].nodeValue;
if (key === 'color') {
options.opacity = parseInt(value.substring(0, 2), 16) / 255.0;
options.color = "#" + value.substring(2, 8);
} else if (key === 'width') {
options.weight = value;
} else if (key === 'Icon') {
ioptions = _parse(e);
if (ioptions.href) { options.href = ioptions.href; }
} else if (key === 'href') {
options.href = value;
}
}
}
options.fillOpacity = 0;
return options;
}
 
for (var i = 0; i < sl.length; i++) {
var e = sl[i], el;
var options = {}, poptions = {}, ioptions = {};
el = e.getElementsByTagName("LineStyle");
if (el && el[0]) { options = _parse(el[0]); }
el = e.getElementsByTagName("PolyStyle");
if (el && el[0]) { poptions = _parse(el[0]); }
if (poptions.color) { options.fillColor = poptions.color; }
if (poptions.opacity) { options.fillOpacity = poptions.opacity; }
el = e.getElementsByTagName("IconStyle");
if (el && el[0]) { ioptions = _parse(el[0]); }
if (ioptions.href) {
// save anchor info until the image is loaded
options.icon = new L.KMLIcon({
iconUrl: ioptions.href,
shadowUrl: null,
iconAnchorRef: {x: ioptions.x, y: ioptions.y},
iconAnchorType: {x: ioptions.xunits, y: ioptions.yunits}
});
}
style['#' + e.getAttribute('id')] = options;
}
return style;
},
 
parseFolder: function (xml, style) {
var el, layers = [], l;
el = xml.getElementsByTagName('Folder');
for (var i = 0; i < el.length; i++) {
if (!this._check_folder(el[i], xml)) { continue; }
l = this.parseFolder(el[i], style);
if (l) { layers.push(l); }
}
el = xml.getElementsByTagName('Placemark');
for (var j = 0; j < el.length; j++) {
if (!this._check_folder(el[j], xml)) { continue; }
l = this.parsePlacemark(el[j], xml, style);
if (l) { layers.push(l); }
}
if (!layers.length) { return; }
if (layers.length === 1) { return layers[0]; }
return new L.FeatureGroup(layers);
},
 
parsePlacemark: function (place, xml, style) {
var i, j, el, options = {};
el = place.getElementsByTagName('styleUrl');
for (i = 0; i < el.length; i++) {
var url = el[i].childNodes[0].nodeValue;
for (var a in style[url])
{
// for jshint
if (true)
{
options[a] = style[url][a];
}
}
}
var layers = [];
 
var parse = ['LineString', 'Polygon', 'Point'];
for (j in parse) {
// for jshint
if (true)
{
var tag = parse[j];
el = place.getElementsByTagName(tag);
for (i = 0; i < el.length; i++) {
var l = this["parse" + tag](el[i], xml, options);
if (l) { layers.push(l); }
}
}
}
 
if (!layers.length) {
return;
}
var layer = layers[0];
if (layers.length > 1) {
layer = new L.FeatureGroup(layers);
}
 
var name, descr = "";
el = place.getElementsByTagName('name');
if (el.length) {
name = el[0].childNodes[0].nodeValue;
}
el = place.getElementsByTagName('description');
for (i = 0; i < el.length; i++) {
for (j = 0; j < el[i].childNodes.length; j++) {
descr = descr + el[i].childNodes[j].nodeValue;
}
}
 
/*if (name) {
layer.bindPopup("<h2>" + name + "</h2>" + descr);
}*/
 
return layer;
},
 
parseCoords: function (xml) {
var el = xml.getElementsByTagName('coordinates');
return this._read_coords(el[0]);
},
 
parseLineString: function (line, xml, options) {
var coords = this.parseCoords(line);
if (!coords.length) { return; }
return new L.Polyline(coords, options);
},
 
parsePoint: function (line, xml, options) {
var el = line.getElementsByTagName('coordinates');
if (!el.length) {
return;
}
var ll = el[0].childNodes[0].nodeValue.split(',');
return new L.KMLMarker(new L.LatLng(ll[1], ll[0]), options);
},
 
parsePolygon: function (line, xml, options) {
var el, polys = [], inner = [], i, coords;
el = line.getElementsByTagName('outerBoundaryIs');
for (i = 0; i < el.length; i++) {
coords = this.parseCoords(el[i]);
if (coords) {
polys.push(coords);
}
}
el = line.getElementsByTagName('innerBoundaryIs');
for (i = 0; i < el.length; i++) {
coords = this.parseCoords(el[i]);
if (coords) {
inner.push(coords);
}
}
if (!polys.length) {
return;
}
if (options.fillColor) {
options.fill = true;
}
if (polys.length === 1) {
return new L.Polygon(polys.concat(inner), options);
}
return new L.MultiPolygon(polys, options);
},
 
getLatLngs: function (xml) {
var el = xml.getElementsByTagName('coordinates');
var coords = [];
for (var j = 0; j < el.length; j++) {
// text might span many childnodes
coords = coords.concat(this._read_coords(el[j]));
}
return coords;
},
 
_read_coords: function (el) {
var text = "", coords = [], i;
for (i = 0; i < el.childNodes.length; i++) {
text = text + el.childNodes[i].nodeValue;
}
text = text.split(/[\s\n]+/);
for (i = 0; i < text.length; i++) {
var ll = text[i].split(',');
if (ll.length < 2) {
continue;
}
coords.push(new L.LatLng(ll[1], ll[0]));
}
return coords;
}
 
});
 
L.KMLIcon = L.Icon.extend({
 
createIcon: function () {
var img = this._createIcon('icon');
img.onload = function () {
var i = new Image();
i.src = this.src;
this.style.width = i.width + 'px';
this.style.height = i.height + 'px';
 
if (this.anchorType.x === 'UNITS_FRACTION' || this.anchorType.x === 'fraction') {
img.style.marginLeft = (-this.anchor.x * i.width) + 'px';
}
if (this.anchorType.y === 'UNITS_FRACTION' || this.anchorType.x === 'fraction') {
img.style.marginTop = (-(1 - this.anchor.y) * i.height) + 'px';
}
this.style.display = "";
};
return img;
},
 
_setIconStyles: function (img, name) {
L.Icon.prototype._setIconStyles.apply(this, [img, name])
// save anchor information to the image
img.anchor = this.options.iconAnchorRef;
img.anchorType = this.options.iconAnchorType;
}
});
 
 
L.KMLMarker = L.Marker.extend({
options: {
icon: new L.KMLIcon.Default()
}
});
 
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/widget/modules/carto/squelettes/scripts/leaflet.markercluster.js
New file
0,0 → 1,6
/*
Copyright (c) 2012, Smartrak, David Leaver
Leaflet.markercluster is an open-source JavaScript library for Marker Clustering on leaflet powered maps.
https://github.com/danzel/Leaflet.markercluster
*/
(function(){L.MarkerClusterGroup=L.FeatureGroup.extend({options:{maxClusterRadius:80,iconCreateFunction:null,spiderfyOnMaxZoom:!0,showCoverageOnHover:!0,zoomToBoundsOnClick:!0,singleMarkerMode:!1,disableClusteringAtZoom:null,removeOutsideVisibleBounds:!0,animateAddingMarkers:!1,spiderfyDistanceMultiplier:1,polygonOptions:{}},initialize:function(t){L.Util.setOptions(this,t),this.options.iconCreateFunction||(this.options.iconCreateFunction=this._defaultIconCreateFunction),L.FeatureGroup.prototype.initialize.call(this,[]),this._inZoomAnimation=0,this._needsClustering=[],this._needsRemoving=[],this._currentShownBounds=null},addLayer:function(t){if(t instanceof L.LayerGroup){var e=[];for(var i in t._layers)e.push(t._layers[i]);return this.addLayers(e)}if(!this._map)return this._needsClustering.push(t),this;if(this.hasLayer(t))return this;this._unspiderfy&&this._unspiderfy(),this._addLayer(t,this._maxZoom);var n=t,r=this._map.getZoom();if(t.__parent)for(;n.__parent._zoom>=r;)n=n.__parent;return this._currentShownBounds.contains(n.getLatLng())&&(this.options.animateAddingMarkers?this._animationAddLayer(t,n):this._animationAddLayerNonAnimated(t,n)),this},removeLayer:function(t){return this._map?t.__parent?(this._unspiderfy&&(this._unspiderfy(),this._unspiderfyLayer(t)),this._removeLayer(t,!0),t._icon&&(L.FeatureGroup.prototype.removeLayer.call(this,t),t.setOpacity(1)),this):this:(!this._arraySplice(this._needsClustering,t)&&this.hasLayer(t)&&this._needsRemoving.push(t),this)},addLayers:function(t){var e,i,n;if(!this._map)return this._needsClustering=this._needsClustering.concat(t),this;for(e=0,i=t.length;i>e;e++)if(n=t[e],!this.hasLayer(n)&&(this._addLayer(n,this._maxZoom),n.__parent&&2===n.__parent.getChildCount())){var r=n.__parent.getAllChildMarkers(),s=r[0]===n?r[1]:r[0];L.FeatureGroup.prototype.removeLayer.call(this,s)}for(e in this._layers)n=this._layers[e],n instanceof L.MarkerCluster&&n._iconNeedsUpdate&&n._updateIcon();return this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds),this},removeLayers:function(t){var e,i,n;if(!this._map){for(e=0,i=t.length;i>e;e++)this._arraySplice(this._needsClustering,t[e]);return this}for(e=0,i=t.length;i>e;e++)n=t[e],n.__parent&&(this._removeLayer(n,!0,!0),n._icon&&(L.FeatureGroup.prototype.removeLayer.call(this,n),n.setOpacity(1)));this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds);for(e in this._layers)n=this._layers[e],n instanceof L.MarkerCluster&&n._updateIcon();return this},clearLayers:function(){this._map||(this._needsClustering=[],delete this._gridClusters,delete this._gridUnclustered),this._noanimationUnspiderfy&&this._noanimationUnspiderfy();for(var t in this._layers)L.FeatureGroup.prototype.removeLayer.call(this,this._layers[t]);return this.eachLayer(function(t){delete t.__parent}),this._map&&this._generateInitialClusters(),this},getBounds:function(){var t=new L.LatLngBounds;if(this._topClusterLevel)t.extend(this._topClusterLevel._bounds);else for(var e=this._needsClustering.length-1;e>=0;e--)t.extend(this._needsClustering[e].getLatLng());return t},eachLayer:function(t,e){var i,n=this._needsClustering.slice();for(this._topClusterLevel&&this._topClusterLevel.getAllChildMarkers(n),i=n.length-1;i>=0;i--)t.call(e,n[i])},hasLayer:function(t){if(t._noHas)return!1;var e,i=this._needsClustering;for(e=i.length-1;e>=0;e--)if(i[e]===t)return!0;for(i=this._needsRemoving,e=i.length-1;e>=0;e--)if(i[e]===t)return!1;return!(!t.__parent||t.__parent._group!==this)},zoomToShowLayer:function(t,e){var i=function(){if((t._icon||t.__parent._icon)&&!this._inZoomAnimation)if(this._map.off("moveend",i,this),this.off("animationend",i,this),t._icon)e();else if(t.__parent._icon){var n=function(){this.off("spiderfied",n,this),e()};this.on("spiderfied",n,this),t.__parent.spiderfy()}};t._icon?e():t.__parent._zoom<this._map.getZoom()?(this._map.on("moveend",i,this),t._icon||this._map.panTo(t.getLatLng())):(this._map.on("moveend",i,this),this.on("animationend",i,this),this._map.setView(t.getLatLng(),t.__parent._zoom+1),t.__parent.zoomToBounds())},onAdd:function(t){this._map=t;var e,i,n;for(this._gridClusters||this._generateInitialClusters(),e=0,i=this._needsRemoving.length;i>e;e++)n=this._needsRemoving[e],this._removeLayer(n);for(this._needsRemoving=[],e=0,i=this._needsClustering.length;i>e;e++)n=this._needsClustering[e],n.__parent||this._addLayer(n,this._maxZoom);this._needsClustering=[],this._map.on("zoomend",this._zoomEnd,this),this._map.on("moveend",this._moveEnd,this),this._spiderfierOnAdd&&this._spiderfierOnAdd(),this._bindEvents(),this._zoom=this._map.getZoom(),this._currentShownBounds=this._getExpandedVisibleBounds(),this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds)},onRemove:function(t){t.off("zoomend",this._zoomEnd,this),t.off("moveend",this._moveEnd,this),this._unbindEvents(),this._map._mapPane.className=this._map._mapPane.className.replace(" leaflet-cluster-anim",""),this._spiderfierOnRemove&&this._spiderfierOnRemove();for(var e in this._layers)L.FeatureGroup.prototype.removeLayer.call(this,this._layers[e]);this._map=null},_arraySplice:function(t,e){for(var i=t.length-1;i>=0;i--)if(t[i]===e)return t.splice(i,1),!0},_removeLayer:function(t,e,i){var n=this._gridClusters,r=this._gridUnclustered,s=this._map;if(e)for(var o=this._maxZoom;o>=0&&r[o].removeObject(t,s.project(t.getLatLng(),o));o--);var a,l=t.__parent,_=l._markers;for(this._arraySplice(_,t);l&&(l._childCount--,!(0>l._zoom));)e&&1>=l._childCount?(a=l._markers[0]===t?l._markers[1]:l._markers[0],n[l._zoom].removeObject(l,s.project(l._cLatLng,l._zoom)),r[l._zoom].addObject(a,s.project(a.getLatLng(),l._zoom)),this._arraySplice(l.__parent._childClusters,l),l.__parent._markers.push(a),a.__parent=l.__parent,l._icon&&(L.FeatureGroup.prototype.removeLayer.call(this,l),i||L.FeatureGroup.prototype.addLayer.call(this,a))):(l._recalculateBounds(),i&&l._icon||l._updateIcon()),l=l.__parent;delete t.__parent},_propagateEvent:function(t){t.target instanceof L.MarkerCluster&&(t.type="cluster"+t.type),L.FeatureGroup.prototype._propagateEvent.call(this,t)},_defaultIconCreateFunction:function(t){var e=t.getChildCount(),i=" marker-cluster-";return i+=10>e?"small":100>e?"medium":"large",new L.DivIcon({html:"<div><span>"+e+"</span></div>",className:"marker-cluster"+i,iconSize:new L.Point(40,40)})},_bindEvents:function(){var t=null,e=this._map,i=this.options.spiderfyOnMaxZoom,n=this.options.showCoverageOnHover,r=this.options.zoomToBoundsOnClick;(i||r)&&this.on("clusterclick",function(t){e.getMaxZoom()===e.getZoom()?i&&t.layer.spiderfy():r&&t.layer.zoomToBounds()},this),n&&(this.on("clustermouseover",function(i){this._inZoomAnimation||(t&&e.removeLayer(t),i.layer.getChildCount()>2&&i.layer!==this._spiderfied&&(t=new L.Polygon(i.layer.getConvexHull(),this.options.polygonOptions),e.addLayer(t)))},this),this.on("clustermouseout",function(){t&&(e.removeLayer(t),t=null)},this),e.on("zoomend",function(){t&&(e.removeLayer(t),t=null)},this),e.on("layerremove",function(i){t&&i.layer===this&&(e.removeLayer(t),t=null)},this))},_unbindEvents:function(){var t=this.options.spiderfyOnMaxZoom,e=this.options.showCoverageOnHover,i=this.options.zoomToBoundsOnClick,n=this._map;(t||i)&&this.off("clusterclick",null,this),e&&(this.off("clustermouseover",null,this),this.off("clustermouseout",null,this),n.off("zoomend",null,this),n.off("layerremove",null,this))},_zoomEnd:function(){this._map&&(this._mergeSplitClusters(),this._zoom=this._map._zoom,this._currentShownBounds=this._getExpandedVisibleBounds())},_moveEnd:function(){if(!this._inZoomAnimation){var t=this._getExpandedVisibleBounds();this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,this._zoom,t),this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,t),this._currentShownBounds=t}},_generateInitialClusters:function(){var t=this._map.getMaxZoom(),e=this.options.maxClusterRadius;this.options.disableClusteringAtZoom&&(t=this.options.disableClusteringAtZoom-1),this._maxZoom=t,this._gridClusters={},this._gridUnclustered={};for(var i=t;i>=0;i--)this._gridClusters[i]=new L.DistanceGrid(e),this._gridUnclustered[i]=new L.DistanceGrid(e);this._topClusterLevel=new L.MarkerCluster(this,-1)},_addLayer:function(t,e){var i,n,r=this._gridClusters,s=this._gridUnclustered;for(this.options.singleMarkerMode&&(t.options.icon=this.options.iconCreateFunction({getChildCount:function(){return 1},getAllChildMarkers:function(){return[t]}}));e>=0;e--){i=this._map.project(t.getLatLng(),e);var o=r[e].getNearObject(i);if(o)return o._addChild(t),t.__parent=o,void 0;if(o=s[e].getNearObject(i)){var a=o.__parent;a&&this._removeLayer(o,!1);var l=new L.MarkerCluster(this,e,o,t);r[e].addObject(l,this._map.project(l._cLatLng,e)),o.__parent=l,t.__parent=l;var _=l;for(n=e-1;n>a._zoom;n--)_=new L.MarkerCluster(this,n,_),r[n].addObject(_,this._map.project(o.getLatLng(),n));for(a._addChild(_),n=e;n>=0&&s[n].removeObject(o,this._map.project(o.getLatLng(),n));n--);return}s[e].addObject(t,i)}this._topClusterLevel._addChild(t),t.__parent=this._topClusterLevel},_mergeSplitClusters:function(){this._zoom<this._map._zoom?(this._animationStart(),this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,this._zoom,this._getExpandedVisibleBounds()),this._animationZoomIn(this._zoom,this._map._zoom)):this._zoom>this._map._zoom?(this._animationStart(),this._animationZoomOut(this._zoom,this._map._zoom)):this._moveEnd()},_getExpandedVisibleBounds:function(){if(!this.options.removeOutsideVisibleBounds)return this.getBounds();var t=this._map,e=t.getBounds(),i=e._southWest,n=e._northEast,r=L.Browser.mobile?0:Math.abs(i.lat-n.lat),s=L.Browser.mobile?0:Math.abs(i.lng-n.lng);return new L.LatLngBounds(new L.LatLng(i.lat-r,i.lng-s,!0),new L.LatLng(n.lat+r,n.lng+s,!0))},_animationAddLayerNonAnimated:function(t,e){if(e===t)L.FeatureGroup.prototype.addLayer.call(this,t);else if(2===e._childCount){e._addToMap();var i=e.getAllChildMarkers();L.FeatureGroup.prototype.removeLayer.call(this,i[0]),L.FeatureGroup.prototype.removeLayer.call(this,i[1])}else e._updateIcon()}}),L.MarkerClusterGroup.include(L.DomUtil.TRANSITION?{_animationStart:function(){this._map._mapPane.className+=" leaflet-cluster-anim",this._inZoomAnimation++},_animationEnd:function(){this._map&&(this._map._mapPane.className=this._map._mapPane.className.replace(" leaflet-cluster-anim","")),this._inZoomAnimation--,this.fire("animationend")},_animationZoomIn:function(t,e){var i,n=this,r=this._getExpandedVisibleBounds();this._topClusterLevel._recursively(r,t,0,function(s){var o,a=s._latlng,l=s._markers;for(s._isSingleParent()&&t+1===e?(L.FeatureGroup.prototype.removeLayer.call(n,s),s._recursivelyAddChildrenToMap(null,e,r)):(s.setOpacity(0),s._recursivelyAddChildrenToMap(a,e,r)),i=l.length-1;i>=0;i--)o=l[i],r.contains(o._latlng)||L.FeatureGroup.prototype.removeLayer.call(n,o)}),this._forceLayout();var s,o;n._topClusterLevel._recursivelyBecomeVisible(r,e);for(s in n._layers)o=n._layers[s],o instanceof L.MarkerCluster||!o._icon||o.setOpacity(1);n._topClusterLevel._recursively(r,t,e,function(t){t._recursivelyRestoreChildPositions(e)}),setTimeout(function(){n._topClusterLevel._recursively(r,t,0,function(t){L.FeatureGroup.prototype.removeLayer.call(n,t),t.setOpacity(1)}),n._animationEnd()},200)},_animationZoomOut:function(t,e){this._animationZoomOutSingle(this._topClusterLevel,t-1,e),this._topClusterLevel._recursivelyAddChildrenToMap(null,e,this._getExpandedVisibleBounds()),this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,t,this._getExpandedVisibleBounds())},_animationZoomOutSingle:function(t,e,i){var n=this._getExpandedVisibleBounds();t._recursivelyAnimateChildrenInAndAddSelfToMap(n,e+1,i);var r=this;this._forceLayout(),t._recursivelyBecomeVisible(n,i),setTimeout(function(){if(1===t._childCount){var s=t._markers[0];s.setLatLng(s.getLatLng()),s.setOpacity(1)}else t._recursively(n,i,0,function(t){t._recursivelyRemoveChildrenFromMap(n,e+1)});r._animationEnd()},200)},_animationAddLayer:function(t,e){var i=this;L.FeatureGroup.prototype.addLayer.call(this,t),e!==t&&(e._childCount>2?(e._updateIcon(),this._forceLayout(),this._animationStart(),t._setPos(this._map.latLngToLayerPoint(e.getLatLng())),t.setOpacity(0),setTimeout(function(){L.FeatureGroup.prototype.removeLayer.call(i,t),t.setOpacity(1),i._animationEnd()},200)):(this._forceLayout(),i._animationStart(),i._animationZoomOutSingle(e,this._map.getMaxZoom(),this._map.getZoom())))},_forceLayout:function(){L.Util.falseFn(document.body.offsetWidth)}}:{_animationStart:function(){},_animationZoomIn:function(t,e){this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,t),this._topClusterLevel._recursivelyAddChildrenToMap(null,e,this._getExpandedVisibleBounds())},_animationZoomOut:function(t,e){this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,t),this._topClusterLevel._recursivelyAddChildrenToMap(null,e,this._getExpandedVisibleBounds())},_animationAddLayer:function(t,e){this._animationAddLayerNonAnimated(t,e)}}),L.MarkerCluster=L.Marker.extend({initialize:function(t,e,i,n){L.Marker.prototype.initialize.call(this,i?i._cLatLng||i.getLatLng():new L.LatLng(0,0),{icon:this}),this._group=t,this._zoom=e,this._markers=[],this._childClusters=[],this._childCount=0,this._iconNeedsUpdate=!0,this._bounds=new L.LatLngBounds,i&&this._addChild(i),n&&this._addChild(n)},getAllChildMarkers:function(t){t=t||[];for(var e=this._childClusters.length-1;e>=0;e--)this._childClusters[e].getAllChildMarkers(t);for(var i=this._markers.length-1;i>=0;i--)t.push(this._markers[i]);return t},getChildCount:function(){return this._childCount},zoomToBounds:function(){this._group._map.fitBounds(this._bounds)},getBounds:function(){var t=new L.LatLngBounds;return t.extend(this._bounds),t},_updateIcon:function(){this._iconNeedsUpdate=!0,this._icon&&this.setIcon(this)},createIcon:function(){return this._iconNeedsUpdate&&(this._iconObj=this._group.options.iconCreateFunction(this),this._iconNeedsUpdate=!1),this._iconObj.createIcon()},createShadow:function(){return this._iconObj.createShadow()},_addChild:function(t,e){this._iconNeedsUpdate=!0,this._expandBounds(t),t instanceof L.MarkerCluster?(e||(this._childClusters.push(t),t.__parent=this),this._childCount+=t._childCount):(e||this._markers.push(t),this._childCount++),this.__parent&&this.__parent._addChild(t,!0)},_expandBounds:function(t){var e,i=t._wLatLng||t._latlng;t instanceof L.MarkerCluster?(this._bounds.extend(t._bounds),e=t._childCount):(this._bounds.extend(i),e=1),this._cLatLng||(this._cLatLng=t._cLatLng||i);var n=this._childCount+e;this._wLatLng?(this._wLatLng.lat=(i.lat*e+this._wLatLng.lat*this._childCount)/n,this._wLatLng.lng=(i.lng*e+this._wLatLng.lng*this._childCount)/n):this._latlng=this._wLatLng=new L.LatLng(i.lat,i.lng)},_addToMap:function(t){t&&(this._backupLatlng=this._latlng,this.setLatLng(t)),this._noHas=!0,L.FeatureGroup.prototype.addLayer.call(this._group,this),delete this._noHas},_recursivelyAnimateChildrenIn:function(t,e,i){this._recursively(t,0,i-1,function(t){var i,n,r=t._markers;for(i=r.length-1;i>=0;i--)n=r[i],n._icon&&(n._setPos(e),n.setOpacity(0))},function(t){var i,n,r=t._childClusters;for(i=r.length-1;i>=0;i--)n=r[i],n._icon&&(n._setPos(e),n.setOpacity(0))})},_recursivelyAnimateChildrenInAndAddSelfToMap:function(t,e,i){this._recursively(t,i,0,function(n){n._recursivelyAnimateChildrenIn(t,n._group._map.latLngToLayerPoint(n.getLatLng()).round(),e),n._isSingleParent()&&e-1===i?(n.setOpacity(1),n._recursivelyRemoveChildrenFromMap(t,e)):n.setOpacity(0),n._addToMap()})},_recursivelyBecomeVisible:function(t,e){this._recursively(t,0,e,null,function(t){t.setOpacity(1)})},_recursivelyAddChildrenToMap:function(t,e,i){this._recursively(i,-1,e,function(n){if(e!==n._zoom)for(var r=n._markers.length-1;r>=0;r--){var s=n._markers[r];i.contains(s._latlng)&&(t&&(s._backupLatlng=s.getLatLng(),s.setLatLng(t),s.setOpacity(0)),s._noHas=!0,L.FeatureGroup.prototype.addLayer.call(n._group,s),delete s._noHas)}},function(e){e._addToMap(t)})},_recursivelyRestoreChildPositions:function(t){for(var e=this._markers.length-1;e>=0;e--){var i=this._markers[e];i._backupLatlng&&(i.setLatLng(i._backupLatlng),delete i._backupLatlng)}if(t-1===this._zoom)for(var n=this._childClusters.length-1;n>=0;n--)this._childClusters[n]._restorePosition();else for(var r=this._childClusters.length-1;r>=0;r--)this._childClusters[r]._recursivelyRestoreChildPositions(t)},_restorePosition:function(){this._backupLatlng&&(this.setLatLng(this._backupLatlng),delete this._backupLatlng)},_recursivelyRemoveChildrenFromMap:function(t,e,i){var n,r;this._recursively(t,-1,e-1,function(t){for(r=t._markers.length-1;r>=0;r--)n=t._markers[r],i&&i.contains(n._latlng)||(L.FeatureGroup.prototype.removeLayer.call(t._group,n),n.setOpacity(1))},function(t){for(r=t._childClusters.length-1;r>=0;r--)n=t._childClusters[r],i&&i.contains(n._latlng)||((!L.FeatureGroup.prototype.hasLayer||L.FeatureGroup.prototype.hasLayer.call(t._group,n))&&L.FeatureGroup.prototype.removeLayer.call(t._group,n),n.setOpacity(1))})},_recursively:function(t,e,i,n,r){var s,o,a=this._childClusters,l=this._zoom;if(e>l)for(s=a.length-1;s>=0;s--)o=a[s],t.intersects(o._bounds)&&o._recursively(t,e,i,n,r);else if(n&&n(this),r&&this._zoom===i&&r(this),i>l)for(s=a.length-1;s>=0;s--)o=a[s],t.intersects(o._bounds)&&o._recursively(t,e,i,n,r)},_recalculateBounds:function(){var t,e=this._markers,i=this._childClusters;for(this._bounds=new L.LatLngBounds,delete this._wLatLng,t=e.length-1;t>=0;t--)this._expandBounds(e[t]);for(t=i.length-1;t>=0;t--)this._expandBounds(i[t])},_isSingleParent:function(){return this._childClusters.length>0&&this._childClusters[0]._childCount===this._childCount}}),L.DistanceGrid=function(t){this._cellSize=t,this._sqCellSize=t*t,this._grid={},this._objectPoint={}},L.DistanceGrid.prototype={addObject:function(t,e){var i=this._getCoord(e.x),n=this._getCoord(e.y),r=this._grid,s=r[n]=r[n]||{},o=s[i]=s[i]||[],a=L.Util.stamp(t);this._objectPoint[a]=e,o.push(t)},updateObject:function(t,e){this.removeObject(t),this.addObject(t,e)},removeObject:function(t,e){var i,n,r=this._getCoord(e.x),s=this._getCoord(e.y),o=this._grid,a=o[s]=o[s]||{},l=a[r]=a[r]||[];for(delete this._objectPoint[L.Util.stamp(t)],i=0,n=l.length;n>i;i++)if(l[i]===t)return l.splice(i,1),1===n&&delete a[r],!0},eachObject:function(t,e){var i,n,r,s,o,a,l,_=this._grid;for(i in _){o=_[i];for(n in o)for(a=o[n],r=0,s=a.length;s>r;r++)l=t.call(e,a[r]),l&&(r--,s--)}},getNearObject:function(t){var e,i,n,r,s,o,a,l,_=this._getCoord(t.x),h=this._getCoord(t.y),u=this._objectPoint,d=this._sqCellSize,p=null;for(e=h-1;h+1>=e;e++)if(r=this._grid[e])for(i=_-1;_+1>=i;i++)if(s=r[i])for(n=0,o=s.length;o>n;n++)a=s[n],l=this._sqDist(u[L.Util.stamp(a)],t),d>l&&(d=l,p=a);return p},_getCoord:function(t){return Math.floor(t/this._cellSize)},_sqDist:function(t,e){var i=e.x-t.x,n=e.y-t.y;return i*i+n*n}},function(){L.QuickHull={getDistant:function(t,e){var i=e[1].lat-e[0].lat,n=e[0].lng-e[1].lng;return n*(t.lat-e[0].lat)+i*(t.lng-e[0].lng)},findMostDistantPointFromBaseLine:function(t,e){var i,n,r,s=0,o=null,a=[];for(i=e.length-1;i>=0;i--)n=e[i],r=this.getDistant(n,t),r>0&&(a.push(n),r>s&&(s=r,o=n));return{maxPoint:o,newPoints:a}},buildConvexHull:function(t,e){var i=[],n=this.findMostDistantPointFromBaseLine(t,e);return n.maxPoint?(i=i.concat(this.buildConvexHull([t[0],n.maxPoint],n.newPoints)),i=i.concat(this.buildConvexHull([n.maxPoint,t[1]],n.newPoints))):[t]},getConvexHull:function(t){var e,i=!1,n=!1,r=null,s=null;for(e=t.length-1;e>=0;e--){var o=t[e];(i===!1||o.lat>i)&&(r=o,i=o.lat),(n===!1||n>o.lat)&&(s=o,n=o.lat)}var a=[].concat(this.buildConvexHull([s,r],t),this.buildConvexHull([r,s],t));return a}}}(),L.MarkerCluster.include({getConvexHull:function(){var t,e,i,n=this.getAllChildMarkers(),r=[],s=[];for(i=n.length-1;i>=0;i--)e=n[i].getLatLng(),r.push(e);for(t=L.QuickHull.getConvexHull(r),i=t.length-1;i>=0;i--)s.push(t[i][0]);return s}}),L.MarkerCluster.include({_2PI:2*Math.PI,_circleFootSeparation:25,_circleStartAngle:Math.PI/6,_spiralFootSeparation:28,_spiralLengthStart:11,_spiralLengthFactor:5,_circleSpiralSwitchover:9,spiderfy:function(){if(this._group._spiderfied!==this&&!this._group._inZoomAnimation){var t,e=this.getAllChildMarkers(),i=this._group,n=i._map,r=n.latLngToLayerPoint(this._latlng);this._group._unspiderfy(),this._group._spiderfied=this,e.length>=this._circleSpiralSwitchover?t=this._generatePointsSpiral(e.length,r):(r.y+=10,t=this._generatePointsCircle(e.length,r)),this._animationSpiderfy(e,t)}},unspiderfy:function(t){this._group._inZoomAnimation||(this._animationUnspiderfy(t),this._group._spiderfied=null)},_generatePointsCircle:function(t,e){var i,n,r=this._group.options.spiderfyDistanceMultiplier*this._circleFootSeparation*(2+t),s=r/this._2PI,o=this._2PI/t,a=[];for(a.length=t,i=t-1;i>=0;i--)n=this._circleStartAngle+i*o,a[i]=new L.Point(e.x+s*Math.cos(n),e.y+s*Math.sin(n))._round();return a},_generatePointsSpiral:function(t,e){var i,n=this._group.options.spiderfyDistanceMultiplier*this._spiralLengthStart,r=this._group.options.spiderfyDistanceMultiplier*this._spiralFootSeparation,s=this._group.options.spiderfyDistanceMultiplier*this._spiralLengthFactor,o=0,a=[];for(a.length=t,i=t-1;i>=0;i--)o+=r/n+5e-4*i,a[i]=new L.Point(e.x+n*Math.cos(o),e.y+n*Math.sin(o))._round(),n+=this._2PI*s/o;return a},_noanimationUnspiderfy:function(){var t,e,i=this._group,n=i._map,r=this.getAllChildMarkers();for(this.setOpacity(1),e=r.length-1;e>=0;e--)t=r[e],L.FeatureGroup.prototype.removeLayer.call(i,t),t._preSpiderfyLatlng&&(t.setLatLng(t._preSpiderfyLatlng),delete t._preSpiderfyLatlng),t.setZIndexOffset(0),t._spiderLeg&&(n.removeLayer(t._spiderLeg),delete t._spiderLeg)}}),L.MarkerCluster.include(L.DomUtil.TRANSITION?{SVG_ANIMATION:function(){return(""+document.createElementNS("http://www.w3.org/2000/svg","animate")).indexOf("SVGAnimate")>-1}(),_animationSpiderfy:function(t,e){var i,n,r,s,o=this,a=this._group,l=a._map,_=l.latLngToLayerPoint(this._latlng);for(i=t.length-1;i>=0;i--)n=t[i],n.setZIndexOffset(1e6),n.setOpacity(0),n._noHas=!0,L.FeatureGroup.prototype.addLayer.call(a,n),delete n._noHas,n._setPos(_);a._forceLayout(),a._animationStart();var h=L.Path.SVG?0:.3,u=L.Path.SVG_NS;for(i=t.length-1;i>=0;i--)if(s=l.layerPointToLatLng(e[i]),n=t[i],n._preSpiderfyLatlng=n._latlng,n.setLatLng(s),n.setOpacity(1),r=new L.Polyline([o._latlng,s],{weight:1.5,color:"#222",opacity:h}),l.addLayer(r),n._spiderLeg=r,L.Path.SVG&&this.SVG_ANIMATION){var d=r._path.getTotalLength();r._path.setAttribute("stroke-dasharray",d+","+d);var p=document.createElementNS(u,"animate");p.setAttribute("attributeName","stroke-dashoffset"),p.setAttribute("begin","indefinite"),p.setAttribute("from",d),p.setAttribute("to",0),p.setAttribute("dur",.25),r._path.appendChild(p),p.beginElement(),p=document.createElementNS(u,"animate"),p.setAttribute("attributeName","stroke-opacity"),p.setAttribute("attributeName","stroke-opacity"),p.setAttribute("begin","indefinite"),p.setAttribute("from",0),p.setAttribute("to",.5),p.setAttribute("dur",.25),r._path.appendChild(p),p.beginElement()}if(o.setOpacity(.3),L.Path.SVG)for(this._group._forceLayout(),i=t.length-1;i>=0;i--)n=t[i]._spiderLeg,n.options.opacity=.5,n._path.setAttribute("stroke-opacity",.5);setTimeout(function(){a._animationEnd(),a.fire("spiderfied")},200)},_animationUnspiderfy:function(t){var e,i,n,r=this._group,s=r._map,o=t?s._latLngToNewLayerPoint(this._latlng,t.zoom,t.center):s.latLngToLayerPoint(this._latlng),a=this.getAllChildMarkers(),l=L.Path.SVG&&this.SVG_ANIMATION;for(r._animationStart(),this.setOpacity(1),i=a.length-1;i>=0;i--)e=a[i],e._preSpiderfyLatlng&&(e.setLatLng(e._preSpiderfyLatlng),delete e._preSpiderfyLatlng,e._setPos(o),e.setOpacity(0),l&&(n=e._spiderLeg._path.childNodes[0],n.setAttribute("to",n.getAttribute("from")),n.setAttribute("from",0),n.beginElement(),n=e._spiderLeg._path.childNodes[1],n.setAttribute("from",.5),n.setAttribute("to",0),n.setAttribute("stroke-opacity",0),n.beginElement(),e._spiderLeg._path.setAttribute("stroke-opacity",0)));setTimeout(function(){var t=0;for(i=a.length-1;i>=0;i--)e=a[i],e._spiderLeg&&t++;for(i=a.length-1;i>=0;i--)e=a[i],e._spiderLeg&&(e.setOpacity(1),e.setZIndexOffset(0),t>1&&L.FeatureGroup.prototype.removeLayer.call(r,e),s.removeLayer(e._spiderLeg),delete e._spiderLeg);r._animationEnd()},200)}}:{_animationSpiderfy:function(t,e){var i,n,r,s,o=this._group,a=o._map;for(i=t.length-1;i>=0;i--)s=a.layerPointToLatLng(e[i]),n=t[i],n._preSpiderfyLatlng=n._latlng,n.setLatLng(s),n.setZIndexOffset(1e6),L.FeatureGroup.prototype.addLayer.call(o,n),r=new L.Polyline([this._latlng,s],{weight:1.5,color:"#222"}),a.addLayer(r),n._spiderLeg=r;this.setOpacity(.3),o.fire("spiderfied")},_animationUnspiderfy:function(){this._noanimationUnspiderfy()}}),L.MarkerClusterGroup.include({_spiderfied:null,_spiderfierOnAdd:function(){this._map.on("click",this._unspiderfyWrapper,this),this._map.options.zoomAnimation?this._map.on("zoomstart",this._unspiderfyZoomStart,this):this._map.on("zoomend",this._unspiderfyWrapper,this),L.Path.SVG&&!L.Browser.touch&&this._map._initPathRoot()},_spiderfierOnRemove:function(){this._map.off("click",this._unspiderfyWrapper,this),this._map.off("zoomstart",this._unspiderfyZoomStart,this),this._map.off("zoomanim",this._unspiderfyZoomAnim,this),this._unspiderfy()},_unspiderfyZoomStart:function(){this._map&&this._map.on("zoomanim",this._unspiderfyZoomAnim,this)},_unspiderfyZoomAnim:function(t){L.DomUtil.hasClass(this._map._mapPane,"leaflet-touching")||(this._map.off("zoomanim",this._unspiderfyZoomAnim,this),this._unspiderfy(t))},_unspiderfyWrapper:function(){this._unspiderfy()},_unspiderfy:function(t){this._spiderfied&&this._spiderfied.unspiderfy(t)},_noanimationUnspiderfy:function(){this._spiderfied&&this._spiderfied._noanimationUnspiderfy()},_unspiderfyLayer:function(t){t._spiderLeg&&(L.FeatureGroup.prototype.removeLayer.call(this,t),t.setOpacity(1),t.setZIndexOffset(0),this._map.removeLayer(t._spiderLeg),delete t._spiderLeg)}})})(this);
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/widget/modules/carto/squelettes/scripts/L.Control.Zoomslider.js
New file
0,0 → 1,248
/*
*
* Copyright (c) 2012, Kartena AB
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
 
L.Control.Zoomslider = (function(){
 
var Knob = L.Draggable.extend({
initialize: function (element, steps, stepHeight, knobHeight) {
var sliderHeight = steps * stepHeight;
L.Draggable.prototype.initialize.call(this, element, element);
 
this._element = element;
this._maxValue = steps - 1;
 
// conversion parameters
// the conversion is just a common linear function.
this._k = -stepHeight;
this._m = sliderHeight - (stepHeight + knobHeight) / 2;
 
this.on('predrag', function() {
this._newPos.x = 0;
this._newPos.y = this._adjust(this._newPos.y);
}, this);
},
 
_adjust: function (y) {
var value = Math.round(this._toValue(y));
value = Math.max(0, Math.min(this._maxValue, value));
return this._toY(value);
},
 
// y = k*v + m
_toY: function (value) {
return this._k * value + this._m;
},
// v = (y - m) / k
_toValue: function (y) {
return (y - this._m) / this._k;
},
 
setPosition: function (y) {
L.DomUtil.setPosition(this._element,
L.point(0, this._adjust(y)));
},
 
setValue: function (v) {
this.setPosition(this._toY(v));
},
 
getValue: function () {
return this._toValue(L.DomUtil.getPosition(this._element).y);
}
});
 
var Zoomslider = L.Control.extend({
options: {
position: 'topleft',
// Height of zoom-slider.png in px
stepHeight: 9,
// Height of the knob div in px
knobHeight: 5,
styleNS: 'leaflet-control-zoomslider'
},
 
onAdd: function (map) {
var container = L.DomUtil.create('div', this.options.styleNS + ' leaflet-bar');
 
L.DomEvent.disableClickPropagation(container);
 
this._map = map;
 
this._zoomInButton = this._createZoomButton(
'in', 'top', container, this._zoomIn);
 
this._sliderElem = L.DomUtil.create(
'div',
this.options.styleNS + "-slider leaflet-bar-part",
container);
 
this._zoomOutButton = this._createZoomButton(
'out', 'bottom', container, this._zoomOut);
 
map .on('layeradd layerremove', this._refresh, this)
.on("zoomend", this._updateSlider, this)
.on("zoomend", this._updateDisabled, this)
.whenReady(this._createSlider, this)
.whenReady(this._createKnob, this)
.whenReady(this._updateSlider, this)
.whenReady(this._updateDisabled, this);
 
return container;
},
 
onRemove: function (map) {
map .off("zoomend", this._updateSlider)
.off("zoomend", this._updateDisabled)
.off('layeradd layerremove', this._refresh);
},
 
_refresh: function () {
// TODO: listen to zoomlevelschange-event instead in 0.6.x
this._map
.removeControl(this)
.addControl(this);
},
_zoomLevels: function(){
return this._map.getMaxZoom() - this._map.getMinZoom() + 1;
},
 
_createSlider: function () {
var zoomLevels = this._zoomLevels();
 
// No tilelayer probably
if(zoomLevels == Infinity){
return;
}
 
this._sliderBody = L.DomUtil.create('div',
this.options.styleNS + '-slider-body',
this._sliderElem);
this._sliderBody.style.height
= (this.options.stepHeight * zoomLevels) + "px";
L.DomEvent.on(this._sliderBody, 'click', this._onSliderClick, this);
},
 
_createKnob: function () {
var knobElem,
zoomLevels = this._zoomLevels();
 
// No tilelayer probably
if(zoomLevels == Infinity) {
return;
}
 
knobElem = L.DomUtil.create('div', this.options.styleNS + '-slider-knob',
this._sliderBody);
L.DomEvent.disableClickPropagation(knobElem);
 
this._knob = new Knob(knobElem,
this._zoomLevels(),
this.options.stepHeight,
this.options.knobHeight)
.on('dragend', this._updateZoom, this);
this._knob.enable();
},
 
_onSliderClick: function (e) {
var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e);
var y = L.DomEvent.getMousePosition(first).y
- L.DomUtil.getViewportOffset(this._sliderBody).y; // Cache this?
this._knob.setPosition(y);
this._updateZoom();
},
 
_zoomIn: function (e) {
this._map.zoomIn(e.shiftKey ? 3 : 1);
},
_zoomOut: function (e) {
this._map.zoomOut(e.shiftKey ? 3 : 1);
},
 
_createZoomButton: function (zoomDir, end, container, fn) {
var barPart = 'leaflet-bar-part',
classDef = this.options.styleNS + '-' + zoomDir
+ ' ' + barPart
+ ' ' + barPart + '-' + end,
title = 'Zoom ' + zoomDir,
link = L.DomUtil.create('a', classDef, container);
link.href = '#';
link.title = title;
 
L.DomEvent
.on(link, 'click', L.DomEvent.preventDefault)
.on(link, 'click', fn, this);
 
return link;
},
_toZoomLevel: function (sliderValue) {
return sliderValue + this._map.getMinZoom();
},
_toSliderValue: function (zoomLevel) {
return zoomLevel - this._map.getMinZoom();
},
 
_updateZoom: function(){
this._map.setZoom(this._toZoomLevel(this._knob.getValue()));
},
_updateSlider: function(){
if(this._knob){
this._knob.setValue(this._toSliderValue(this._map.getZoom()));
}
},
_updateDisabled: function () {
var map = this._map,
className = this.options.styleNS + '-disabled';
 
L.DomUtil.removeClass(this._zoomInButton, className);
L.DomUtil.removeClass(this._zoomOutButton, className);
 
if (map.getZoom() === map.getMinZoom()) {
L.DomUtil.addClass(this._zoomOutButton, className);
}
if (map.getZoom() === map.getMaxZoom()) {
L.DomUtil.addClass(this._zoomInButton, className);
}
}
});
return Zoomslider;
})();
 
L.Map.mergeOptions({
zoomControl: false,
zoomsliderControl: true
});
 
L.Map.addInitHook(function () {
if (this.options.zoomsliderControl) {
this.zoomsliderControl = new L.Control.Zoomslider();
this.addControl(this.zoomsliderControl);
}
});
 
L.control.zoomslider = function (options) {
return new L.Control.Zoomslider(options);
};
/trunk/widget/modules/carto/squelettes/scripts/cluster.js
New file
0,0 → 1,117
 
 
L.Cluster = L.Marker.extend({
initialize: function(marker, options) {
L.Marker.prototype.initialize.call(this, marker, options);
this._markers = [this];
},
ajouterMarker: function(marker) {
this._markers.push(marker);
},
recupererMarkers: function() {
return this._markers;
},
obtenirNombreMarkers: function() {
return this._markers.length;
},
supprimerSource: function(sourceSupression) {
var index = 0;
while (index < this._markers.length) {
if (this._markers[index].source == sourceSupression) {
this._markers.splice(index, 1);
} else {
index ++;
}
}
if (this._markers.length == 0) {
if (this._map != null) {
this._map.removeLayer(this);
//this._map.getPanes().markerPane.removeChild(this._icon);
}
delete this;
}
},
supprimer: function() {
while (this._markers.length > 0) {
this._markers.splice(0, 1);
}
if (this._map != null) {
this._map.removeLayer(this);
//this._map.getPanes().markerPane.removeChild(this._icon);
}
delete this;
}
});
 
 
 
L.ClusterGroup = L.FeatureGroup.extend({
initialize: function(layers) {
L.FeatureGroup.prototype.initialize.call(this, layers);
this._distance = 10;
this._resolution = 0;
this._nombreClusters = 0;
},
 
ajouterPoint: function(layer) {
if (this._resolution == 0) {
this._resolution = (2 * Math.PI * 6378137) / (256 * Math.pow(2, this._map.getZoom()));
}
var seuilCluster = this._distance * this._resolution;
if (typeof(layer._latlng) != 'undefined') {
var indexClusterPlusProche = this._chercherVoisinPlusProche(layer);
var ajoute = false;
if (indexClusterPlusProche != null) {
var distance = this._layers[indexClusterPlusProche].getLatLng().distanceTo(layer.getLatLng());
if (distance < seuilCluster) {
this._layers[indexClusterPlusProche].ajouterMarker(layer);
ajoute = true;
}
}
if (!ajoute) {
this._layers[this._nombreClusters] = layer;
this._nombreClusters ++;
}
}
},
_chercherVoisinPlusProche: function(layer) {
var distance = -1;
var plusProche = null;
for (var numeroLayer in this._layers) {
if (typeof(this._layers[numeroLayer]) != 'undefined') {
var centre = this._layers[numeroLayer].getLatLng();
if (distance == -1 || centre.distanceTo(layer.getLatLng()) < distance) {
plusProche = numeroLayer;
distance = centre.distanceTo(layer.getLatLng());
}
}
}
return plusProche;
},
afficherClusters: function() {
for (var numeroLayer in this._layers) {
if (typeof(this._layers[numeroLayer]) != 'undefined') {
var layer = this._layers[numeroLayer];
if (layer.obtenirNombreMarkers() > 1) {
layer.setIcon(new L.Icon({ iconUrl : clusterImageUrl, iconSize : [20, 20] }))
}
layer.addTo(map);
}
}
},
supprimerPoint: function(layer) {
layer.supprimer();
}
});
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/widget/modules/carto/squelettes/scripts/carto.js
New file
0,0 → 1,960
var map = null,
optionsCoucheOSM = {
attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors,'
+ ' <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
maxZoom: 18
},
optionsCoucheGoogle = {
attribution: 'Map data &copy;'+new Date().getFullYear()+' <a href="http://maps.google.com">Google</a>',
maxZoom: 18
},
coucheOSM = new L.TileLayer("http://a.tile.openstreetmap.org/{z}/{x}/{y}.png",
optionsCoucheOSM),
coucheRelief = new L.TileLayer("http://c.tile3.opencyclemap.org/landscape/{z}/{x}/{y}.png",
optionsCoucheOSM),
coucheSatellite = new L.TileLayer("http://mt1.google.com/vt/lyrs=y@218131653&hl=fr&src=app&x={x}&y={y}&z={z}",
optionsCoucheGoogle),
optionsCarte = {
center : new L.LatLng(46, 2),
zoom : 6,
minZoom : 3,
maxBounds : [[-85.051129, -180], [85.051129, 180]],
layers : [coucheOSM]
},
zoom = 6,
legende = null,
coucheDepartement = null,
infoBulle = null;
 
var coucheSites = null,
sources = new Object(),
typeSite = 'maille',
overlays = [];
 
var requeteChargementPoints = null,
timer = null,
ancienneRequete = null,
deplacement = true,
url = '';
 
 
 
 
$(document).ready(function() {
initialiserWidget();
});
 
$(window).resize(function() {
dimensionnerCarte();
});
 
function initialiserWidget() {
initialiserCarte();
chargerLimitesCommunales();
initialiserPanneauControle();
initialiserSources();
initialiserListeners();
chargerLocalisations();
}
 
function initialiserCarte() {
dimensionnerCarte();
map = L.map('map', optionsCarte);
coucheSatellite.addTo(map);
coucheRelief.addTo(map);
coucheOSM.addTo(map);
var echelle = new L.Control.Scale({
maxWidth : 50,
metric : true,
imperial : false,
updateWhenIdle : true
});
map.addControl(echelle);
zoom = map.getZoom();
}
 
function dimensionnerCarte() {
$('#map').height($(window).height());
$('#map').width($(window).width());
}
 
function initialiserListeners() {
map.on('moveend', surChangementVueCarte);
map.on('zoomend', surChangementVueCarte);
map.on('popupclose', function(e) {
masquerInfoBulle();
programmerRafraichissementCarte();
});
}
 
function initialiserPanneauControle() {
var baseMaps = {
"Satellite" : coucheSatellite,
"Relief" : coucheRelief,
"Plan" : coucheOSM
};
 
var overlayMaps = {};
for (var index = 0; index < listeSources.length; index ++) {
sources[listeSources[index]] = estValeurDansTableau(source, listeSources[index]);
overlayMaps[listeSources[index]] = new L.LayerGroup();
}
L.control.layers(baseMaps, overlayMaps).addTo(map);
coucheOSM.bringToFront();
map.removeLayer(coucheRelief);
map.removeLayer(coucheOSM);
// garder par defaut la couche plan google comme selectionnee dans le panel
var selecteursFonds = $('.leaflet-control-layers-base .leaflet-control-layers-selector');
selecteursFonds[0].checked = true;
selecteursFonds[1].checked = false;
selecteursFonds[2].checked = false;
}
 
function chargerLimitesCommunales() {
coucheDepartement = new L.KML(null, {async : true}).addTo(map);
if (urlsLimitesCommunales != null) {
coucheDepartement.addKMLFiles(urlsLimitesCommunales);
}
}
 
function initialiserSources() {
overlays = $('.leaflet-control-layers-overlays .leaflet-control-layers-selector');
$.each(overlays, function (index, input) {
input.value = listeSources[index];
input.id = 'overlay' + (index+1);
var lien = '<a href="' + liensVersSources[index] + '" target="_blank">' + nomListeSources[index] + '</a>';
$('#overlay' + (index+1) + ' ~ span').html(lien);
input.checked = sources[listeSources[index]];
input.onclick = function(event) {
changerSource(event.target.value);
}
});
}
 
function changerSource(projetClique) {
var indexProjetClique;
for (var index = 0; index < overlays.length; index ++) {
if (overlays[index].value == projetClique) {
indexProjetClique = index;
}
}
masquerInfoBulle();
sources[projetClique] = overlays[indexProjetClique].checked;
if (sources[projetClique] == true) {
programmerRafraichissementCarte(projetClique);
} else {
if (requeteEnCours()) {
stopperRequeteAjax();
}
supprimerFeaturesSource(projetClique);
}
}
 
function supprimerFeaturesSource(source) {
if (coucheSites != null) {
coucheSites.eachLayer(function(layer) {
if (layer.typeSite == 'maille') {
retirerStationsEtObservations(layer, source);
} else {
layer.supprimerSource(source, coucheSites);
if (layer._map == 'null') {
couheSites.removeLayer(layer);
}
}
});
if (typeSite == 'maille') {
var nombreMailles = calculerNombreMaillesVisibles();
if (nombreMailles == 0) {
coucheSites.clearLayers();
masquerLegende();
typeSite = 'point';
}
}
}
}
 
function retirerStationsEtObservations(maille, sourceRetrait) {
var sources = maille.properties.source;
var nombreStations = 0;
for (var index = 0; index < sources.length; index ++) {
var source = sources[index];
if (source == sourceRetrait) {
delete maille.properties.stations[source];
delete maille.properties.observations[source];
} else if (typeof(maille.properties.stations[source]) != 'undefined') {
nombreStations += parseInt(maille.properties.stations[source]);
}
}
if (nombreStations == 0) {
coucheSites.removeLayer(maille);
} else {
colorerMaille(maille)
genererInfobulle(maille);
}
}
 
function calculerNombreMaillesVisibles() {
var nombreMailles = 0;
coucheSites.eachLayer(function(layer) {
if($(layer._path).attr('fill-opacity') != '0') {
nombreMailles ++;
}
});
return nombreMailles;
}
 
function estValeurDansTableau(tableau, valeur) {
var index;
for (index = 0; index < tableau.length && tableau[index] != valeur; index ++);
return (tableau.length > 0 && index != tableau.length);
}
 
//************************************
// requetes stations
 
function surChangementVueCarte() {
programmerRafraichissementCarte();
}
 
function programmerRafraichissementCarte(source) {
$('#tooltip').css('display', 'none');
source = (source == null || source == 'null') ? null : source;
if (timer != null) {
window.clearTimeout(timer);
}
if (requeteChargementPoints != null) {
stopperRequeteAjax();
}
var nombreSourcesVisibles = 0;
for (var index = 0; index < overlays.length; index ++) {
if (overlays[index].checked) {
nombreSourcesVisibles ++;
}
}
if (source == null) {
timer = window.setTimeout("chargerLocalisations()", 100);
} else {
timer = window.setTimeout("chargerSource('"+source+"')", 100);
}
}
 
function stopperRequeteAjax() {
requeteChargementPoints.abort();
requeteChargementPoints = null;
}
 
function chargerLocalisations() {
if (requeteEnCours()) {
requeteChargementPoints.abort();
}
afficherMessageChargement('stations');
if (!(ancienneRequete != null && ancienneRequete[1] == map.getZoom()
&& map.getBounds().intersects(ancienneRequete[0]))) {
supprimerFeatures();
deplacement = false;
}
var bboxRequete = calculerBboxRequete();
var parametres = {
"bbox" : bboxRequete,
"zoom" : map.getZoom(),
"source" : recupererSourcesActivees(),
"num_taxon" : numTaxon,
"nn" : nn,
"referentiel" : referentiel,
"dept" : dept,
"auteur" : auteur,
"date_debut" : dateDebut,
"date_fin" : dateFin,
"nb_jours" : nbJours
};
if (deplacement == true) {
parametres.format = typeSite;
}
ancienneRequete = [map.getBounds(), map.getZoom()];
url = urlBase + "stations?" + convertirEnParametresUrl(parametres);
fonctionCallback = traiterDonneesStations;
executerAJAX();
}
 
function supprimerFeatures() {
if (coucheSites != null) {
coucheSites.clearLayers();
coucheSites = null;
}
}
 
function recupererSourcesActivees(sourceAIgnorer) {
sourceAIgnorer = typeof(sourceAIgnorer) == 'undefined' ? '' : sourceAIgnorer;
var sourcesActivees = [];
for (var index = 0; index < overlays.length; index ++) {
if (overlays[index].checked == true && overlays[index].value != sourceAIgnorer) {
sourcesActivees.push(overlays[index].value);
}
}
return sourcesActivees.join(',');
}
 
function chargerSource(sourceAjout) {
if (requeteEnCours()) {
requeteChargementPoints.abort();
}
afficherMessageChargement('stations');
var bboxRequete = determinerCoordonneesBordure();
var parametres = {
"bbox" : bboxRequete,
"zoom" : map.getZoom(),
"format" : typeSite,
"source" : sourceAjout,
"num_taxon" : numTaxon,
"nn" : nn,
"referentiel" : referentiel,
"dept" : dept,
"auteur" : auteur,
"date_debut" : dateDebut,
"date_fin" : dateFin,
"nb_jours" : nbJours
};
ancienneRequete = [map.getBounds(), map.getZoom()];
url = urlBase + "stations?" + convertirEnParametresUrl(parametres);
fonctionCallback = traiterRetourChargementSource;
executerAJAX();
}
 
function calculerBboxRequete() {
var bordure = map.getBounds();
var bboxRequete = "";
if (ancienneRequete != null && ancienneRequete[1] == map.getZoom()
&& bordure.intersects(ancienneRequete[0])) {
bboxRequete = calculerIntersectionRectangle(ancienneRequete[0], bordure);
} else {
bboxRequete = determinerCoordonneesBordure();
}
return bboxRequete;
}
 
function calculerIntersectionRectangle(rectangle1, rectangle2) {
var bbox1 = [rectangle2.getSouthWest().lng.toFixed(6), rectangle2.getSouthWest().lat.toFixed(6),
rectangle2.getNorthEast().lng.toFixed(6), rectangle2.getNorthEast().lat.toFixed(6)];
var bbox2 = [rectangle2.getSouthWest().lng.toFixed(6), rectangle2.getSouthWest().lat.toFixed(6),
rectangle2.getNorthEast().lng.toFixed(6), rectangle2.getNorthEast().lat.toFixed(6)];
if (rectangle2.getSouthWest().lng >= rectangle1.getSouthWest().lng
&& rectangle2.getSouthWest().lng <= rectangle1.getNorthEast().lng) {
bbox2[0] = bbox1[2] = rectangle1.getNorthEast().lng.toFixed(6);
if (rectangle2.getSouthWest().lat >= rectangle1.getSouthWest().lat
&& rectangle2.getSouthWest().lat <= rectangle1.getNorthEast().lat) {
bbox1[1] = rectangle1.getNorthEast().lat.toFixed(6);
} else {
bbox1[3] = rectangle1.getSouthWest().lat.toFixed(6);
}
} else {
bbox2[0] = bbox1[2] = rectangle1.getSouthWest().lng.toFixed(6);
if (rectangle2.getSouthWest().lat >= rectangle1.getSouthWest().lat
&& rectangle2.getSouthWest().lat <= rectangle1.getNorthEast().lat) {
bbox2[1] = rectangle1.getNorthEast().lat.toFixed(6);
} else {
bbox2[3] = rectangle1.getSouthWest().lat.toFixed(6);
}
}
return bbox1.join(',')+'|'+bbox2.join(',');
}
 
function determinerCoordonneesBordure() {
var ouest = map.getBounds().getSouthWest().lng.toFixed(6),
sud = Math.max(map.getBounds().getSouthWest().lat, -85.051129).toFixed(6),
est = map.getBounds().getNorthEast().lng.toFixed(6),
nord = Math.min(map.getBounds().getNorthEast().lat, 85.051129).toFixed(6);
// appliquer les limites possibles de la projection actuellement utilisee aux coordonnees
// longitudes ouest et est de la bbox (permettra d'eviter de renvoyer des messages d'erreur)
if (ouest < -180) {
ouest += 360;
} else if (ouest > 180) {
ouest -= 360;
}
if (est < -180) {
est += 360;
} else if (est > 180) {
est -= 360;
}
return [ouest, sud, est, nord].join(',');
}
 
function afficherMessageChargement(element) {
if ($("#zone-chargement").css('display') == 'none') {
var divTmplElement = 'tpl-chargement-' + element;
$("#zone-chargement").append($("#" + divTmplElement).text());
$("#zone-chargement").css('display', 'block');
}
}
 
function masquerMessageChargement() {
$("#zone-chargement").css('display', 'none');
$("#zone-chargement").children().remove();
}
 
function executerAJAX() {
if (requeteEnCours()) {
requeteChargementPoints.abort();
}
requeteChargementPoints = $.getJSON(url).complete(function() {
fonctionCallback();
});
}
 
function requeteEnCours() {
return (requeteChargementPoints != null && requeteChargementPoints.readyState != 4);
}
 
function estStatutRequeteOK() {
return ((requeteChargementPoints.status == 200 || requeteChargementPoints.status == 304)
|| requeteChargementPoints.status == 0);
}
 
function convertirEnParametresUrl(objet) {
var parametresUrl = '';
for (attribut in objet) {
if (typeof(objet[attribut]) == 'function' || typeof(objet[attribut]) == 'undefined' ||
objet[attribut] == null || objet[attribut] == '*' || objet[attribut] == 0)
continue;
parametresUrl += (parametresUrl == '' ? '' : '&') + attribut + "=" + objet[attribut];
}
return parametresUrl;
};
 
function traiterDonneesStations() {
masquerMessageChargement();
masquerLegende();
if (deplacement == true) {
supprimerFeaturesHorsBbox();
}
deplacement = true;
var texte = requeteChargementPoints.responseText;
if (!estStatutRequeteOK()) {
alert(texte);
} else {
var donneesJSON = eval("(function(){return " + texte + ";})()");
if (donneesJSON != null && donneesJSON.features.length > 0) {
ajouterStationsSurCarte(donneesJSON);
}
}
}
 
function traiterRetourChargementSource() {
masquerMessageChargement();
var texte = requeteChargementPoints.responseText;
if (!estStatutRequeteOK()) {
alert(texte);
} else {
var donneesJSON = eval("(function(){return " + texte + ";})()");
if (donneesJSON != null && donneesJSON.features.length > 0) {
var formatRetourDifferent = donneesJSON.stats.formeDonnees != typeSite;
ajouterStationsSurCarte(donneesJSON);
if (formatRetourDifferent) {
var sourceAIgnorer = donneesJSON.stats.source[0];
var sourcesARecharger = recupererSourcesActivees(sourceAIgnorer);
if (sourcesARecharger.length > 0) {
rechargerSources(sourcesARecharger);
}
}
}
}
}
 
function supprimerFeaturesHorsBbox() {
var bordure = map.getBounds();
var layersRestants = 0;
if (coucheSites != null) {
coucheSites.eachLayer(function(layer) {
if (typeof(layer._latlng) != 'undefined') {
if (bordure.contains(layer.getLatLng())) {
layersRestants ++;
} else {
coucheSites.supprimerPoint(layer);
}
} else {
if (bordure.intersects(layer.getBounds())) {
layersRestants ++;
} else {
coucheSites.removeLayer(layer);
}
}
});
}
if (layersRestants == 0) {
coucheSites = null;
}
}
 
function rechargerSources(sourcesARecharger) {
var listeSourcesASupprimer = sourcesARecharger.split(',');
for (var index = 0; index < listeSourcesASupprimer.length; index ++) {
supprimerFeaturesSource(listeSourcesASupprimer[index]);
}
chargerSource(sourcesARecharger);
}
 
function ajouterStationsSurCarte(donnees) {
typeSite = donnees.stats.formeDonnees;
if (coucheSites == null) {
coucheSites = (typeSite == 'maille') ? new L.FeatureGroup() : new L.ClusterGroup();
map.addLayer(coucheSites);
}
for (var index = 0; index < donnees.features.length; index ++) {
var feature = donnees.features[index];
if (typeSite == 'maille') {
traiterMaille(feature);
} else {
ajouterPoint(feature);
}
}
if (donnees.features.length > 0) {
afficherLegende();
}
if (typeSite == 'maille') {
genererInfobulleMailles();
} else {
coucheSites.afficherClusters();
}
}
 
// =========================================
// Gestion des mailles
 
function traiterMaille(feature) {
var coordonnees = [];
for (var i = 0; i < feature.geometry.coordinates.length; i++) {
var sommet = new L.LatLng(feature.geometry.coordinates[i][0], feature.geometry.coordinates[i][1]);
coordonnees.push(sommet);
}
var maille = rechercherMailleExistante(coordonnees);
if (maille) {
mettreAJourMaille(maille, feature);
} else {
maille = ajouterMaille(feature, coordonnees);
}
colorerMaille(maille);
}
 
function rechercherMailleExistante(coordonnees) {
var mailleTrouvee = null;
coucheSites.eachLayer(function(layer) {
if ('typeSite' in layer && layer.typeSite == 'maille') {
if (sontMaillesIdentiques(coordonnees, layer._latlngs)) {
mailleTrouvee = layer;
return;
}
}
});
return mailleTrouvee;
}
 
function sontMaillesIdentiques(coordonnees1, coordonnees2) {
return (
coordonnees1[0].lat == coordonnees2[0].lat &&
coordonnees1[0].lng == coordonnees2[0].lng &&
coordonnees1[2].lat == coordonnees2[2].lat &&
coordonnees1[2].lng == coordonnees2[2].lng
);
}
 
function ajouterMaille(feature, coordonnees) {
var maille = new L.Polygon(coordonnees);
var optionsMaille = {
color: '#FFFFFF',
opacity : 0.7,
weight: 1,
fillOpacity : 0.6
};
maille.setStyle(optionsMaille);
maille.typeSite = 'maille';
maille.properties = feature.properties;
coucheSites.addLayer(maille);
return maille;
}
 
function mettreAJourMaille(maille, feature) {
var sources = feature.properties.source;
for (var index = 0; index < sources.length; index ++) {
var source = sources[index];
maille.properties.stations[source] = parseInt(feature.properties.stations[source]);
maille.properties.observations[source] = parseInt(feature.properties.observations[source]);
maille.properties.source.push(source);
}
}
 
function colorerMaille(maille) {
var nombreStations = 0;
var sources = maille.properties.source;
for (var index = 0; index < sources.length; index ++) {
var source = sources[index];
if (typeof(maille.properties.stations[source]) != 'undefined') {
nombreStations += parseInt(maille.properties.stations[source]);
}
}
if (nombreStations > 0) {
maille.on('click', surClicMaille);
maille.setStyle({fillColor : genererCouleur(nombreStations), fillOpacity: 0.45, opacity: 0.7});
} else {
maille.setStyle({fillOpacity: 0, opacity: 0});
maille.off('click');
}
}
 
function genererCouleur(nombrePoints) {
var couleur = {'bleu': 231, 'vert': 224, 'rouge': 64},
seuils = [1, 10, 50 ,100, 500, 1000, 2500],
pas = 26,
position = 0;
for (var index = 1; index < seuils.length-1 && nombrePoints >= seuils[index]; index ++) {
position ++;
}
couleur.vert -= position*pas;
return 'rgb('+couleur.bleu+','+couleur.vert+','+couleur.rouge+')';
}
 
function surClicMaille(event) {
map.fitBounds(event.layer.getBounds());
}
 
function afficherLegende() {
if (legende == null) {
legende = new L.Control({position : 'bottomright'});
legende.onAdd = function(map) {
var contenuHtml = '';
if (typeSite == 'maille') {
contenuHtml = construireContenuHtmlLegendeMailles();
} else {
contenuHtml = construireContenuHtmlLegendePoints();
}
return contenuHtml;
};
map.addControl(legende);
}
}
 
function construireContenuHtmlLegendeMailles() {
var div = L.DomUtil.create('div', 'info');
div.innerHTML = '<h4>' + titreLegende + '</h4>';
var seuils = [1, 10, 50 ,100, 500, 1000, 2500];
var labels = [];
for (var i = 0; i < seuils.length; i ++) {
div.innerHTML +=
'<div class="legend">'+
'<span class="couleur-maille" style="background:' + genererCouleur(seuils[i] + 1) + '">'+
'</span>'+seuils[i]+ (i + 1 < seuils.length ? '&ndash;' + seuils[i + 1] : '+')+
'</div>';
}
return div;
}
 
function masquerLegende() {
if (legende != null) {
map.removeControl(legende);
legende = null;
}
}
 
function genererInfobulleMailles() {
coucheSites.eachLayer(function(layer) {
if (layer.typeSite == 'maille') {
genererInfobulle(layer);
}
});
}
 
function genererInfobulle(maille) {
var sources = maille.properties.source;
var textes = new Array();
for (var index = 0; index < sources.length; index ++) {
var source = sources[index];
if (typeof(maille.properties.stations[source]) != 'undefined') {
textes.push(source+" : "+maille.properties.stations[source]+" stations, "
+maille.properties.observations[source]+" observations");
}
}
var contenu = textes.join('<br />');
maille.on('mouseover', function() {
afficherTooltip(contenu, map.latLngToContainerPoint(maille.getBounds().getSouthWest()));
});
maille.on('mouseout', function() {
$("#tooltip").css('display', 'none');
});
}
 
function afficherTooltip(texte, point) {
$("#tooltip").html(texte);
if ($("#tooltip").css('display') == 'none') {
var x = point.x - 15;
var y = point.y + (typeSite == 'maille' ? 1 : 10);
$("#tooltip").css('display', 'block');
$("#tooltip").css('left', x + 'px');
$("#tooltip").css('top', y + 'px');
}
}
 
 
 
 
// ====================================================================
// Gestion des points
 
function ajouterPoint(feature) {
var iconePoint = new L.Icon({ iconUrl : pointImageUrl, iconSize : [16, 16] }),
iconeCommune = new L.Icon({ iconUrl : communeImageUrl, iconSize : [24, 32] }),
icone = (feature.properties.typeSite == 'STATION') ? iconePoint : iconeCommune,
point = new L.LatLng(feature.geometry.coordinates[0], feature.geometry.coordinates[1]);
var marker = new L.Cluster(point, {
icon : icone,
titre : feature.properties.nom
});
marker.typeSite = feature.properties.typeSite.toLowerCase();
marker.source = feature.properties.source;
marker.on('click', surClicMarqueur);
marker.on('mouseover', function() {
afficherTooltip(marker.options.titre, map.latLngToContainerPoint(marker.getLatLng()));
});
marker.on('mouseout', function() {
$("#tooltip").css('display', 'none');
});
coucheSites.ajouterPoint(marker);
}
 
function construireContenuHtmlLegendePoints() {
var div = L.DomUtil.create('div', 'info');
div.innerHTML =
'<h4>Stations</h4>'+
'<div class="legend"><table>'+
'<tr>'+
'<td class="image-station"><img src="'+communeImageUrl+'" width="24" height="32" /></td>'+
'<td class="label-station">Commune</td>'+
'</tr>'+
'<tr>'+
'<td class="image-station"><img src="'+pointImageUrl+'" /></td>'+
'<td class="label-station">Lieu précis</td>'+
'</tr>'+
'<tr>'+
'<td class="image-station"><img src="'+clusterImageUrl+'" width="20" height="20" /></td>'+
'<td class="label-station">Groupe de stations proches</td>'+
'</tr>'+
'</table></div>';
return div;
}
 
 
function surClicMarqueur(event) {
var nombreMarkers = event.target.recupererMarkers().length;
if (nombreMarkers == 1 || map.getZoom() == map.getMaxZoom()) {
recupererObservations(event.target);
} else {
map.setView(event.target.getLatLng(), Math.min(map.getZoom()+2, map.getMaxZoom()));
}
}
 
function recupererObservations(cluster) {
pointClique = cluster;
var latlng = cluster.getLatLng();
afficherMessageChargement('observations');
var parametres = {
"source" : recupererSourcesCluster(cluster),
"stations" : construireListeStationsCluster(cluster),
"num_taxon" : numTaxon,
"nn" : nn,
"referentiel" : referentiel,
"auteur" : auteur,
"date_debut" : dateDebut,
"date_fin" : dateFin,
"nb_jours" : nbJours
};
url = urlBase + "observations?" + convertirEnParametresUrl(parametres);
fonctionCallback = traiterDonneesObservations;
executerAJAX();
}
 
function recupererSourcesCluster(cluster) {
var markers = cluster.recupererMarkers();
var sourcesCluster = [];
for (var index = 0; index < markers.length; index ++) {
if (sourcesCluster.indexOf(markers[index].source) == -1) {
sourcesCluster.push(markers[index].source);
}
}
return sourcesCluster.join(',');
}
 
function construireListeStationsCluster(cluster) {
var markers = cluster.recupererMarkers();
var listePoints = [];
for (var index = 0; index < markers.length; index ++) {
var latlng = markers[index].getLatLng();
listePoints.push(markers[index].source+":"+markers[index].typeSite+":"+latlng.lng+","+latlng.lat);
}
return listePoints.join('|');
}
 
function traiterDonneesObservations() {
masquerMessageChargement();
var texte = requeteChargementPoints.responseText;
if (!estStatutRequeteOK()) {
alert(texte);
} else {
obsJSON = eval("(function(){return " + texte + ";})()");
if (obsJSON != null) {
viderListeObservations();
if (obsJSON.total > 0) {
doitRafraichirCarte = false;
map.setView(new L.LatLng(pointClique.getLatLng().lat, pointClique.getLatLng().lng), map.getZoom());
afficherInfoBulle();
} else if (infoBulle != null) {
masquerInfoBulle();
}
}
}
}
 
 
 
 
// ====================================================================
// Gestion de l'infobulle
 
var obsJSON = null,
pointClique = null,
obsStation = [],
pagineur = {'limite':100, 'start':0, 'total':0, 'stationId':null, 'format':'tableau'};
 
function afficherInfoBulle() {
var latitude = pointClique.getLatLng().lat;
var longitude = pointClique.getLatLng().lng;
infoBulle = new L.Popup({maxWidth : definirLargeurInfoBulle(), maxHeight : 380});
infoBulle.setLatLng(new L.LatLng(latitude, longitude));
infoBulle.setContent($("#tpl-obs").html());
infoBulle.openOn(map);
remplirContenuPopup();
$('#info-bulle').css('width', '99%');
$('#observations').css('height', '250px');
$('#observations').css('overflow', 'auto');
$('.leaflet-popup-scrolled').css('overflow', 'visible');
}
 
function viderListeObservations() {
obsStation = new Array();
}
 
function definirLargeurInfoBulle() {
var largeurViewPort = $(window).width();
var lageurInfoBulle = null;
if (largeurViewPort < 800) {
largeurInfoBulle = 400;
} else if (largeurViewPort >= 800 && largeurViewPort < 1200) {
largeurInfoBulle = 500;
} else if (largeurViewPort >= 1200) {
largeurInfoBulle = 600;
}
return largeurInfoBulle;
}
 
function redimensionnerPopup() {
$('.leaflet-popup-content*').css('width', definirLargeurInfoBulle());
$('#info-bulle').css('width', '99%');
}
 
function remplirContenuPopup() {
ajouterTableauTriable("#obs-tableau");
ajouterTitre();
afficherTableau();
afficherTexteStationId();
}
 
function masquerInfoBulle() {
if (infoBulle != null && map.hasLayer(infoBulle)) {
map.removeLayer(infoBulle);
}
infoBulle = null;
}
 
function ajouterTitre() {
var texteStationTitre = obsJSON.total + ' observation' + (obsJSON.total > 1 ? 's' : '')
+ ' sur ' + (pointClique.typeSite=='station' ? 'la station : ' : 'la commune : ')
+ pointClique.options.title;
$('#obs-station-titre').text(texteStationTitre);
}
 
function afficherTableau() {
construireListeObservations();
afficherPagination();
afficherObservationsDansHTML();
}
 
function construireListeObservations() {
if (obsStation.length==0) {
// premiere execution de la fonction : faire une copie des objets JSON decrivant les observations
for (var index = 0; index < obsJSON.observations.length; index ++) {
obsStation.push(obsJSON.observations[index]);
}
}
pagineur.total = obsStation.length;
}
 
function afficherPagination() {
$(".navigation").pagination(pagineur.total, {
items_per_page:pagineur.limite,
callback:afficherObservationsDansHTML,
next_text:'Suivant',
prev_text:'Précédent',
prev_show_always:false,
num_edge_entries:1,
num_display_entries:4,
load_first_page:true
});
}
 
function afficherObservationsDansHTML(indexPage) {
$("#obs-tableau-lignes").empty();
if (typeof(indexPage) == 'undefined') {
indexPage = 0;
}
var depart = indexPage * pagineur.limite;
var obsPage = [];
for (var index = depart; index < depart + pagineur.limite; index ++) {
obsPage.push(obsStation[index]);
}
$("#tpl-obs-tableau").tmpl(obsPage).appendTo("#obs-tableau-lignes");
mettreAJourTableauTriable();
}
 
function ajouterTableauTriable() {
$.tablesorter.addParser({
id: 'date_cel',
is: function(s) {
// doit retourner false si le parseur n'est pas autodétecté
return /^\s*\d{2}[\/-]\d{2}[\/-]\d{4}\s*$/.test(s);
},
format: function(date) {
// Transformation date jj/mm/aaaa en aaaa/mm/jj
date = date.replace(/^\s*(\d{2})[\/-](\d{2})[\/-](\d{4})\s*$/, "$3-$2-$1");
// Remplace la date par un nombre de millisecondes pour trier numériquement
return $.tablesorter.formatFloat(new Date(date).getTime());
},
type: 'numeric'
});
$("#obs-tableau").tablesorter({
headers: {
1: {
sorter:'date_cel'
}
}
});
}
 
function mettreAJourTableauTriable() {
$("#obs-tableau").trigger('update');
}
 
function afficherTexteStationId() {
var latitude = pointClique.getLatLng().lat.toFixed(5);
var longitude = pointClique.getLatLng().lng.toFixed(5);
var texteStationId = pointClique.typeSite.toUpperCase() + ':'
+ latitude + '|' + longitude + ', SOURCE:' + pointClique.source;
$('#obs-station-id').text(texteStationId);
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/trunk/widget/modules/carto/squelettes/scripts
New file
Property changes:
Added: svn:ignore
+carto_old.js
/trunk/widget/modules/carto/squelettes/css/carto.css
New file
0,0 → 1,539
@charset "UTF-8";
html {
overflow:hidden;
}
body {
overflow:hidden;
padding:2px;
margin:0;
width:100%;
height:100%;
font-family:Arial;
font-size:12px;
}
h1 {
font-size:1.6em;
}
h2 {
font-size:1.4em;
}
a, a:active, a:visited {
border-bottom:1px dotted #666;
color:#56B80E;
text-decoration:none;
}
a:active {
outline:none;
}
a:focus {
outline:thin dotted;
}
a:hover {
color:#56B80E;
border-bottom:1px dotted #56B80E;
}
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Présentation des listes de définitions */
dl {
width:100%;
margin:0;
}
dt {
float:left;
font-weight:bold;
text-align:top left;
margin-right:0.3em;
line-height:0.8em;
}
dd {
width:auto;
margin:0.5em 0;
line-height:0.8em;
}
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Tableau : */
table {
border:1px solid gray;
border-collapse:collapse;
width:100%;
}
table thead, table tfoot, table tbody {
background-color:Gainsboro;
border:1px solid gray;
}
table tbody {
background-color:#FFF;
}
table th {
font-family:monospace;
border:1px dotted gray;
padding:5px;
background-color:Gainsboro;
}
table td {
font-family:arial;
border:1px dotted gray;
padding:5px;
text-align:left;
}
table caption {
font-family:sans-serif;
}
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Tableau : tablesorter */
th.header {
background:url(../images/tri.png) no-repeat center right;
padding-right:20px;
}
th.headerSortUp {
background:url(../images/tri_croissant.png) no-repeat center right #56B80E;
color:white;
}
th.headerSortDown {
background:url(../images/tri_decroissant.png) no-repeat center right #56B80E;
color:white;
}
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Générique */
.nettoyage{
clear:both;
}
hr.nettoyage{
visibility:hidden;
}
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Carte */
#carte {
padding:0;
margin:0;
position:absolute;
top:35px;
left:24px;
right:0;
bottom:0;
overflow:auto;
}
.bouton {
background-color:white;
border:2px solid black;
cursor:pointer;
text-align:center;
}
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Message de chargement */
#chargement {
margin:25px;
text-align:center;
}
#chargement img{
display:block;
margin:auto;
}
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Avertissement */
#zone-avertissement {
background-color:#4A4B4C;
color:#CCC;
padding:12px;
text-align:justify;
line-height:16px;
}
#zone-avertissement h1{
margin:0;
}
#zone-avertissement a {
border-bottom:1px dotted gainsboro;
}
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Carte titre */
#zone-titre {
padding:0;
margin:0;
position:absolute;
top:20px;
left:0;
width:auto;
height:35px;
overflow:hidden;
background-color:#DDDDDD;
z-index : 3000;
border-radius: 4px;
border: 1px solid black;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05) inset;
display: inline-block;
}
#zone-info {
position:absolute;
top:0;
right:8px;
width:48px;
text-align:right;
}
#zone-info img {
display:inline;
padding:4px;
margin:0;
border:none;
}
#carte-titre {
display:inline-block;
margin:0;
padding:0.2em;
color:black;
}
#carte-titre {/*Hack CSS fonctionne seulement dans ie6, 7 & 8 */
display:inline !hackCssIe6Et7;/*Hack CSS pour ie6 & ie7 */
display /*\**/:inline\9;/*Hack CSS pour ie8 */
}
 
#logo {
position:absolute;
z-index:3000;
top:20px;
left:45px;
}
 
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* message de chargement de donnees */
#zone-chargement {
background-color: white;
border: 5px solid #D7DBEA;
display: none;
height: 70px;
left: 40%;
padding: 10px;
position: fixed;
text-align: center;
top: 40%;
width: 230px;
z-index: 3000;
}
 
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Panneau latéral */
#panneau-lateral {
padding:0;
margin:0;
position:absolute;
top:35px;
left:0;
bottom:0;
width:24px;
overflow:hidden;
background-color:#4A4B4C;
border-right:1px solid grey;
}
#pl-contenu {
display:none;
}
#pl-entete {
height:95px;
}
#pl-corps {
position:absolute;
top:105px;
bottom:0;
overflow:auto;
padding:5px;
width:290px;
}
#pl-ouverture, #pl-fermeture {
position:absolute;
top:0;
height:24px;
width:24px;
text-align:center;
cursor:pointer;
}
#pl-ouverture {
left:0;
background:url(../images/ouverture.png) no-repeat top left #4A4B4C;
height:100%;
}
#pl-fermeture {
display:none;
left:276px;
background:url(../images/fermeture.png) no-repeat top right #4A4B4C;
}
#pl-ouverture span, #pl-fermeture span{
display:none;
}
/* Panneau latéral : balises */
#panneau-lateral h2, #panneau-lateral p {
color:#CCCCCC;}
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Liste des taxons de la carte */
#taxons {
color:#999;
}
#taxons .taxon-actif, #taxons .taxon-actif span {
color:#56B80E;
}
#taxons li span {
border-bottom:1px dotted #666;
color:#CCC;
}
#taxons li span:focus {
outline:thin dotted;
}
#taxons li span:hover {
color:#56B80E;
border-bottom:1px dotted #56B80E;
cursor:pointer;
}
.nt {
display:none;
}
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Pop-up observations */
#info-bulle{
min-height:500px;
width:500px;
}
#observations {
clear: both;
overflow:none;
margin:-1px 0 0 0;
border: 1px solid #AAA;
border-radius:0 0 4px 4px;
}
#obs-pieds-page {
font-size:10px;
color:#CCC;
clear:both;
}
.ui-tabs {
padding:0;
}
.ui-widget-content {
border:0;
}
.ui-widget-header {
background:none;
border:0;
border-bottom:1px solid #AAA;
border-radius:0;
}
.ui-tabs-selected a {
border-bottom:1px solid white;
}
.ui-tabs-selected a:focus {
outline:0;
}
.ui-tabs .ui-tabs-panel {
padding:0.2em;
}
.ui-tabs .ui-tabs-nav li a {
padding: 0.5em 0.6em;
}
#obs h2 {
margin:0;
text-align:center;
}
#observations a {
color:#333;
border-bottom:1px dotted gainsboro;
}
#observations a:hover {
color:#56B80E;
border-bottom:1px dotted #56B80E;
}
.nom-sci{
color:#454341;
font-weight:bold;
}
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Pop-up observations : liste */
.cel-img-principale {
height:0;/*Pour IE*/
}
.cel-img-principale img{
float:right;
height:75px;
width:75px;
padding:1px;
border:1px solid white;
}
#observations .cel-img:hover img{
border: 1px dotted #56B80E;
}
.cel-img-secondaire, .cel-infos{
display: none;
}
ol#obs-liste-lignes {
padding:5px;
margin:0;
}
.champ-nom-sci {
display:none;
}
#obs-liste-lignes li dl {/*Pour IE*/
width:350px;
}
.obs-conteneur{
counter-reset: item;
}
.obs-conteneur .nom-sci:before {
content: counter(item) ". ";
counter-increment: item;
display:block;
float:left;
}
.obs-conteneur li {
display: block;
margin-bottom:1em;
}
 
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Diaporama */
.cel-legende{
text-align:left;
}
.cel-legende-vei{
float:right;
}
.cel-legende p{
color: black;
font-size: 12px;
line-height: 18px;
margin: 0;
}
.cel-legende a, .cel-legende a:active, .cel-legende a:visited {
border-bottom:1px dotted gainsboro;
color:#333;
text-decoration:none;
background-image:none;
}
.cel-legende a:hover {
color:#56B80E;
border-bottom:1px dotted #56B80E;
}
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Plugin Jquery Pagination */
.navigation {
padding:5px;
float:right;
display: block;
}
.pagination {
font-size: 80%;
}
.pagination a {
text-decoration: none;
border: solid 1px #666;
color: #666;
background:gainsboro;
}
.pagination a:hover {
color: white;
background: #56B80E;
}
.pagination a, .pagination span {
display: block;
float: left;
padding: 0.3em 0.5em;
margin-right: 5px;
margin-bottom: 5px;
min-width:1em;
text-align:center;
}
.pagination .current {
background: #4A4B4C;
color: white;
border: solid 1px gainsboro;
}
.pagination .current.prev, .pagination .current.next{
color: #999;
border-color: #999;
background: gainsboro;
}
/*+-----------------------------------------------------------------------------------------------------------------+*/
/* Formulaire de contact */
#form-contact input{
width:300px;
}
#form-contact textarea{
width:300px;
height:200px;
}
#form-contact #fc_envoyer{
width:50px;
float:right;
}
#form-contact #fc_annuler{
width:50px;
float:left;
}
#form-contact label.error {
color:red;
font-weight:bold;
}
#form-contact .info {
padding:5px;
background-color: #4A4B4C;
border: solid 1px #666;
color: white;
white-space: pre-wrap;
width: 300px;
}
 
 
/*+-------------------------------------------------------------------
/* Ajout alex */
 
.info {
padding:6px 8px;
font-size:1em;
background:white;
width:110px;
box-shadow:0 0 15px black;
border-radius:5px;
line-height:18px;
}
.info h4 {
font-size: 1.2em;
margin: 0 0 5px;
color: #555;
}
.legend {
padding :3px;
color:#999;
}
.legend span.couleur-maille {
width:18px;
height:18px;
float:left;
margin-right:8px;
opacity: 0.7;
}
 
.legend table {
border-collapse: separate;
border: none;
}
 
.legend td {
border: none;
}
 
.legend td.image-station {
text-align: center;
}
 
.legend td.label-station {
text-align: left;
font-size: 0.9em;
}
 
#tooltip {
position: absolute;
z-index: 3000;
border: none;
border-radius : 5px;
background-color: lightblue;
padding: 5px;
font-family : sans-serif;
font-size:1.1em;
}
 
#tooltip h3, #tooltip div { margin: 0; }
/trunk/widget/modules/carto/squelettes/css/L.Control.Zoomslider.ie.css
New file
0,0 → 1,29
 
.leaflet-control-zoomslider a, .leaflet-control-zoomslider-slider {
background-color: #eee;
}
.leaflet-control-zoomslider a:hover {
background-color: #fff;
}
.leaflet-control-zoomslider-slider {
padding-top: 4px;
padding-bottom: 4px;
}
 
 
/* IE6-7 specific hacks */
.leaflet-control-zoomslider-slider {
*width: 23px;
}
/* Fix IE6-divs having a too large min height */
.leaflet-control-zoomslider-slider-knob {
*overflow: hidden;
}
 
/* Support for element:after { content: 'text' } */
.leaflet-control-zoomslider-in {
*zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '+');
}
.leaflet-control-zoomslider-out {
*zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '-');
}
/trunk/widget/modules/carto/squelettes/css/L.Control.Zoomslider.css
New file
0,0 → 1,106
/** Slider **/
.leaflet-control-zoomslider-slider {
padding-top: 5px ;
padding-bottom: 5px;
}
 
.leaflet-control-zoomslider-slider-body {
background-image: url(images/zoom-slider.png);
background-repeat: repeat-y;
background-position: center 0px;
height: 100%;
cursor: default;
}
 
.leaflet-control-zoomslider-slider-knob {
width: 13px;
height:5px;
background-color: black;
background-position: center;
-webkit-border-radius: 15px;
border-radius: 15px;
margin-left: 5px;
/*border: 5px; */
position:relative;
}
 
.leaflet-control-zoomslider-slider-body:hover {
cursor: pointer;
}
 
.leaflet-control-zoomslider-slider-knob:hover {
cursor: default;
cursor: -webkit-grab;
cursor: -moz-grab;
}
 
.leaflet-dragging .leaflet-control-zoomslider,
.leaflet-dragging .leaflet-control-zoomslider-slider,
.leaflet-dragging .leaflet-control-zoomslider-slider-body,
.leaflet-dragging .leaflet-control-zoomslider a,
.leaflet-dragging .leaflet-control-zoomslider a.leaflet-control-zoomslider-disabled,
.leaflet-dragging .leaflet-control-zoomslider-slider-knob:hover {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
}
 
/** Leaflet Zoom Styles **/
.leaflet-container .leaflet-control-zoomslider {
margin-left: 13px;
margin-top: 12px;
}
.leaflet-control-zoomslider a {
width: 23px;
height: 22px;
text-align: center;
text-decoration: none;
color: black;
display: block;
}
.leaflet-control-zoomslider a:hover {
background-color: #fff;
color: #777;
}
.leaflet-control-zoomslider-in {
font: bold 19px/24px Arial, Helvetica, sans-serif;
}
.leaflet-control-zoomslider-in:after{
content:"+"
}
.leaflet-control-zoomslider-out {
font: bold 23px/20px Tahoma, Verdana, sans-serif;
}
.leaflet-control-zoomslider-out:after{
content:"-"
}
.leaflet-control-zoomslider a.leaflet-control-zoomslider-disabled {
cursor: default;
color: #bbb;
}
 
/* Touch */
 
.leaflet-touch .leaflet-control-zoomslider-slider-knob {
width:20px;
}
.leaflet-touch .leaflet-control-zoomslider a {
width: 30px;
height: 30px;
}
.leaflet-touch .leaflet-control-zoomslider-in {
font-size: 24px;
line-height: 29px;
}
.leaflet-touch .leaflet-control-zoomslider-out {
font-size: 28px;
line-height: 24px;
}
 
.leaflet-touch .leaflet-control-zoomslider {
box-shadow: none;
}
 
.leaflet-touch .leaflet-control-zoomslider {
border: 4px solid rgba(0,0,0,0.3);
}
/trunk/widget/modules/carto/squelettes/css/MarkerCluster.Default.ie.css
New file
0,0 → 1,22
/* IE 6-8 fallback colors */
.marker-cluster-small {
background-color: rgb(181, 226, 140);
}
.marker-cluster-small div {
background-color: rgb(110, 204, 57);
}
 
.marker-cluster-medium {
background-color: rgb(241, 211, 87);
}
.marker-cluster-medium div {
background-color: rgb(240, 194, 12);
}
 
.marker-cluster-large {
background-color: rgb(253, 156, 115);
}
.marker-cluster-large div {
background-color: rgb(241, 128, 23);
}
 
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/widget/modules/carto/squelettes/css/MarkerCluster.Default.css
New file
0,0 → 1,38
.marker-cluster-small {
background-color: rgba(181, 226, 140, 0.6);
}
.marker-cluster-small div {
background-color: rgba(110, 204, 57, 0.6);
}
 
.marker-cluster-medium {
background-color: rgba(241, 211, 87, 0.6);
}
.marker-cluster-medium div {
background-color: rgba(240, 194, 12, 0.6);
}
 
.marker-cluster-large {
background-color: rgba(253, 156, 115, 0.6);
}
.marker-cluster-large div {
background-color: rgba(241, 128, 23, 0.6);
}
 
.marker-cluster {
background-clip: padding-box;
border-radius: 20px;
}
.marker-cluster div {
width: 30px;
height: 30px;
margin-left: 5px;
margin-top: 5px;
 
text-align: center;
border-radius: 15px;
font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
}
.marker-cluster span {
line-height: 30px;
}
Property changes:
Added: svn:mime-type
+text/plain
\ No newline at end of property
/trunk/widget/modules/carto/squelettes/carto.tpl.html
New file
0,0 → 1,192
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<meta http-equiv="Content-style-type" content="text/css" />
<meta http-equiv="Content-script-type" content="text/javascript" />
<meta http-equiv="Content-language" content="fr" />
 
<title>Carte des observations E-flore : Nouvelle version</title>
<link rel="icon" type="image/png" href="http://resources.tela-botanica.org/tb/img/16x16/favicon.png" />
<link rel="shortcut icon" type="image/x-icon" href="http://resources.tela-botanica.org/tb/img/16x16/favicon.ico" />
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.5/leaflet.css" />
<link rel="stylesheet" href="<?=$url_base?>modules/carto/squelettes/css/L.Control.Zoomslider.css" />
<link rel="stylesheet" href="<?=$url_base?>modules/carto/squelettes/css/MarkerCluster.Default.css" />
<!--[if lte IE 8]>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.5/leaflet.ie.css" />
<link rel="stylesheet" href="<?=$url_base?>modules/carto/squelettes/css/L.Control.Zoomslider.ie.css" />
<link rel="stylesheet" href="<?=$url_base?>modules/carto/squelettes/css/MarkerCluster.Default.ie.css" />
<![endif]-->
<link rel="stylesheet" href="http://www.tela-botanica.org/commun/jquery/fancybox/1.3.4/jquery.fancybox-1.3.4.css" type="text/css" media="screen" />
<link rel="stylesheet" href="http://www.tela-botanica.org/commun/jquery/jquery-ui/1.8.15/css/smoothness/jquery-ui-1.8.15.custom.css" type="text/css" media="screen" />
<link href="<?=$url_base?>modules/carto/squelettes/css/carto.css" rel="stylesheet" type="text/css" media="screen" />
 
<!-- Javascript : bibliothèques -->
<script src="http://cdn.leafletjs.com/leaflet-0.5/leaflet.js"></script>
<script type="text/javascript" src="http://www.tela-botanica.org/commun/jquery/1.6.2/jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="http://www.tela-botanica.org/commun/jquery/tablesorter/2.0.5/jquery.tablesorter.min.js"></script>
<script type="text/javascript" src="http://www.tela-botanica.org/commun/jquery/jquery-ui/1.8.15/js/jquery-ui-1.8.15.custom.min.js"></script>
<script type="text/javascript" src="http://www.tela-botanica.org/commun/jquery/pagination/2.2/jquery.pagination.js"></script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>
<script type="text/javascript">
//<![CDATA[
var source = '<?= $source ?>'.split(',');
var logo = '<?=$logo ?>';
var titreCarte = '<?= ($titre != null) ? addslashes($titre) : null; ?>';
var urlLogo = '<?= ($logo != null) ? "$logo" : null; ?>';
var urlSite = '<?= ($url_site != null) ? "$url_site" : null; ?>';
var nn = '<?= $nn ?>';
var numTaxon = '<?= $num_taxon ?>';
var dept = '<?= $departement ?>';
var auteur = '<?= $auteur ?>';
var referentiel = '<?= $referentiel ?>';
var dateDebut = '<?= $date_debut ?>';
var dateFin = '<?= $date_fin ?>';
var nbJours = '<?=$nb_jours ?>';
var urlBase = '<?= $url_serivce_carto ?>/';
var urlsLimitesCommunales = <?= $urlLimitesCommunales ?>;
var communeImageUrl = '<?= $communeImageUrl ?>';
var pointImageUrl = '<?= $pointImageUrl ?>';
var clusterImageUrl = '<?= $clusterImageUrl ?>';
var liensVersSources = '<?= $liensVersSources ?>'.split(',');
var titreLegende = '<?= $titreLegende ?>';
var listeSources = '<?= $listeSources ?>'.split(',');
var nomListeSources = '<?= $nomListeSources ?>'.split(',');
const ZOOM_MAXIMUM_MAILLAGE = <?= $zoomMaximumMaillage ?>;
const SEUIL_MAILLAGE = <?= $seuilMaillage ?>;
//]]>
</script>
<script src="http://maps.google.com/maps/api/js?v=3.5&sensor=true&language=fr&region=FR" type="text/javascript"></script>
<script src="<?=$url_base?>modules/carto/squelettes/scripts/L.KML.js" type="text/javascript"></script>
<script src="<?=$url_base?>modules/carto/squelettes/scripts/carto.js"></script>
<script src="<?=$url_base?>modules/carto/squelettes/scripts/L.Control.Zoomslider.js" ></script>
<script src="<?=$url_base?>modules/carto/squelettes/scripts/cluster.js" ></script>
</head>
 
<body>
<div id="zone-chargement"></div>
<div id="map"></div>
<!-- +-------------------------------------------------------------------------------------------+ -->
<!-- Blocs chargés à la demande : par défaut avec un style display à none -->
<!-- Squelette du message de chargement des stations et observations -->
<script id="tpl-chargement-stations" type="text/x-jquery-tmpl">
<div id="chargement-stations">
<img src="<?=$url_base?>modules/carto/squelettes/images/chargement.gif" alt="Chargement en cours..." />
<p>Chargement des stations en cours...</p>
</div>
</script>
<script id="tpl-chargement-observations" type="text/x-jquery-tmpl">
<div id="chargement-observations">
<img src="<?=$url_base?>modules/carto/squelettes/images/chargement.gif" alt="Chargement en cours..." />
<p>Chargement des observations en cours...</p>
</div>
</script>
<?php if($logo != null) : ?>
<div id="logo">
<?php if($url_site != null) : ?>
<a href="<?= $url_site; ?>"
title="<?= $url_site; ?>"
onclick="ouvrirNouvelleFenetre(this, event)">
<img height="60px" class="image-logo" src="<?= $logo ?>" alt="logo" />
</a>
<?php else : ?>
<img class="image-logo" src="<?= $logo ?>" alt="logo" />
<?php endif; ?>
</div>
<?php endif; ?>
<?php if($titre !== "0" && $titre != null) : ?>
<div id="zone-titre" class="element-overlay">
<h1 id="carte-titre">
<span id="carte-titre-infos"><?= htmlspecialchars($titre); ?></span>
</h1>
</div>
<?php endif; ?>
<!-- Squelette du contenu d'une info-bulle observation -->
<script id="tpl-obs" type="text/x-jquery-tmpl">
<div id="info-bulle" style="width:{largeur}px;">
<div id="obs">
<h2 id="obs-station-titre">Station</h2>
<div class="navigation">&nbsp;</div>
<div id="observations">
<div id="obs-vue-tableau">
<table id="obs-tableau">
<thead>
<tr>
<th title="Nom scientifique défini par l'utilisateur.">Nom</th>
<th title="Date de l'observation">Date</th>
<th title="Lieu d'observation">Lieu</th>
<th title="Auteur de l'observation">Observateur</th>
<th title="Nom du projet référent">Projet</th>
</tr>
</thead>
<tbody id="obs-tableau-lignes" class="obs-conteneur">
<!-- Insertion des lignes à partir du squelette tpl-obs-tableau -->
</tbody>
</table>
</div>
</div>
<div id="obs-pieds-page">
<p>Id : <span id="obs-station-id">&nbsp;</span></p>
</div>
</div>
</div>
</script>
<!-- Squelette du contenu du tableau des observation -->
<script id="tpl-obs-tableau" type="text/x-jquery-tmpl">
<tr class="cel-obs-${idObs}">
<td>
<span class="nom-sci">&nbsp;
{{if nn != 0}}
<a href="http://www.tela-botanica.org/nn${nn}"
target="_blank">
${nomSci}
</a>
{{else}}
${nomSci}
{{/if}}
</span>
</td>
<td class="date">{{if date}}${date}{{else}}&nbsp;{{/if}}</td>
<td class="lieu">{{if lieu}}${lieu}{{else}}&nbsp;{{/if}}</td>
<td>
{{if observateur}}
{{if observateurId}}
<a class="contact obs-${idObs} contributeur-${observateurId}"
href="#form-contact"
title="Contactez ce contributeur">
${observateur}
</a>
{{else}}
${observateur}
{{/if}}
{{else}}
&nbsp;
{{/if}}
</td>
<td><span>${projet}</span></td>
</tr>
</script>
<!-- Squelette de la liste des taxons -->
<script id="tpl-taxons-liste" type="text/x-jquery-tmpl">
<ol id="taxons">
{{each(index, taxon) taxons}}
<li id="taxon-${taxon.nt}">
<span class="taxon" title="Numéro taxonomique : ${taxon.nt} - Famille : ${taxon.famille}">
${taxon.nom} <span class="nt" title="Numéro taxonomique">${taxon.nt}</span>
</span>
</li>
{{/each}}
</ol>
</script>
<div id="tooltip" style="display:none;"></div>
</body>
</html>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/trunk/widget/modules/carto/squelettes
New file
Property changes:
Added: svn:ignore
+kml
+
+old_carto.tpl.html
/trunk/widget/modules/carto
New file
Property changes:
Added: svn:ignore
+config.ini
/trunk/widget/Widget.php
New file
0,0 → 1,161
<?php
// In : utf8 url_encoded (get et post)
// Out : utf8
/**
* La classe Widget analyser l'url et chage le widget correspondant.
* Format d'url :
* /widget/nom_du_widget?parametres1=ma_valeur1&parametre2=ma_valeur2
* Les widget sont dans des dossiers en minuscule correspondant au nom de la classe du widget.
* Exemple : /widget/carto avec la classe Carto.php dans le dossier carto.
*
*
* @author jpm
*
*/
class Widget {
 
/** Les paramètres de configuration extrait du fichier .ini */
private static $config;
 
/** Le nom du widget demandé. */
private $widget = null;
/** Les chemins où l'autoload doit chercher des classes. */
private static $autoload_chemins = array();
/** Les paramètres de l'url $_GET nettoyés. */
private $parametres = null;
 
/**
* Constructeur.
* Parse le fichier de configuraion "widget.ini" et parse l'url à la recherche du widget demandé.
* @param str iniFile Configuration file to use
*/
public function __construct($fichier_ini = 'widget.ini.php') {
// Chargement de la configuration
self::$config = parse_ini_file($fichier_ini, TRUE);
// Paramêtres de config dynamiques
self::$config['chemins']['baseURLAbsoluDyn'] = 'http://'.$_SERVER['SERVER_NAME'].self::$config['chemins']['baseURL'].'%s';
// Gestion de la mémoire maximum allouée aux services
ini_set('memory_limit', self::$config['parametres']['limiteMemoire']);
// Réglages de PHP
setlocale(LC_ALL, self::$config['parametres']['locale']);
date_default_timezone_set(self::$config['parametres']['fuseauHoraire']);
// Gestion des erreurs
error_reporting(self::$config['parametres']['erreurNiveau']);
if (isset($_SERVER['REQUEST_URI']) && isset($_SERVER['QUERY_STRING'])) {
$url_morceaux = $this->parserUrl();
if (isset($url_morceaux[0])) {
$this->widget = strlen($url_morceaux[0]) == 0 ? $url_morceaux[1] : $url_morceaux[0];
self::$config['chemins']['widgetCourantDossier'] = self::$config['chemins']['widgetsDossier'].strtolower($this->widget).DIRECTORY_SEPARATOR;
$this->chargerWidgetConfig();
}
// Chargement des chemins pour l'autoload
$this->chargerCheminAutoload();
// Enregistrement de la méthode gérant l'autoload des classes
spl_autoload_register(array('Widget', 'chargerClasse'));
// Nettoyage du $_GET (sécurité)
$this->collecterParametres();
} else {
$e = 'Les widget nécessite les variables serveurs suivantes pour fonctionner : REQUEST_URI et QUERY_STRING.';
trigger_error($e, E_USER_ERROR);
}
}
private function parserUrl() {
if (strlen($_SERVER['QUERY_STRING']) == 0) {
$len = strlen($_SERVER['REQUEST_URI']);
} else {
$len = -(strlen($_SERVER['QUERY_STRING']) + 1);
}
$url = substr($_SERVER['REQUEST_URI'], strlen(self::$config['chemins']['baseURL']), $len);
$url_morceaux = explode('/', $url);
return $url_morceaux;
}
private function collecterParametres() {
if (isset($_GET) && $_GET != '') {
$this->nettoyerGet();
$this->parametres = $_GET;
}
}
private function nettoyerGet() {
foreach ($_GET as $cle => $valeur) {
$verifier = array('NULL', "\n", "\r", "\\", '"', "\x00", "\x1a", ';');
$_GET[$cle] = strip_tags(str_replace($verifier, '', $valeur));
}
}
private function chargerCheminAutoload() {
$chemins_communs = explode(';', self::$config['chemins']['autoload']);
$chemins_communs = array_map('trim', $chemins_communs);
array_unshift($chemins_communs, '');
$chemins_widget = array();
if (isset(self::$config[$this->widget]['autoload'])) {
$chemins_widget = explode(';', self::$config[$this->widget]['autoload']);
foreach ($chemins_widget as $cle => $chemin) {
$chemins_widget[$cle] = self::$config['chemins']['widgetCourantDossier'].trim($chemin);
}
}
self::$autoload_chemins = array_merge($chemins_communs, $chemins_widget);
}
/**
* La méthode chargerClasse() charge dynamiquement les classes trouvées dans le code.
* Cette fonction est appelée par php5 quand il trouve une instanciation de classe dans le code.
*
*@param string le nom de la classe appelée.
*@return void le fichier contenant la classe doit être inclu par la fonction.
*/
public static function chargerClasse($classe) {
if (class_exists($classe)) {
return null;
}
foreach (self::$autoload_chemins as $chemin) {
$chemin = $chemin.$classe.'.php';
if (file_exists($chemin)) {
require_once $chemin;
}
}
}
/**
* Execute le widget.
*/
function executer() {
if (!is_null($this->widget)) {
$classe_widget = ucfirst($this->widget);
$fichier_widget = self::$config['chemins']['widgetCourantDossier'].$classe_widget.'.php';
if (file_exists($fichier_widget)) {
include_once $fichier_widget;
if (class_exists($classe_widget)) {
$widget = new $classe_widget(self::$config, $this->parametres);
$widget->executer();
}
}
}
}
/**
* Charge le fichier de config spécifique du wiget et fusionne la config avec celle partagés par l'ensemble des widgets.
*/
private function chargerWidgetConfig() {
$widget_config_ini_fichier = self::$config['chemins']['widgetCourantDossier'].'config.ini';
if (file_exists($widget_config_ini_fichier)) {
$widget_config = parse_ini_file($widget_config_ini_fichier, TRUE);
self::$config = array_merge(self::$config, $widget_config);
}
}
}
?>
/trunk/widget/.htaccess
New file
0,0 → 1,13
<files *.ini>
order deny,allow
deny from all
</files>
 
#AddHandler x-httpd-php5 .php
AddDefaultCharset UTF-8
 
RewriteEngine On
# Redirections générale vers le fichier principal de Widget.
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*$ index.php/
/trunk/widget
New file
Property changes:
Added: svn:ignore
+widget.ini.php
+
+.htaccess
/trunk
Property changes:
Added: svn:ignore
+.project
+france_02.svg
+.buildpath