Transformation CSWeb PostgreSQL
Travail Technique par Assietou DIAGNE
ANSD (Agence Nationale de la Statistique et de la Démographie, Sénégal)
Ce guide documente le travail technique complet réalisé par Assietou DIAGNE pour transformer CSWeb vanilla (MySQL uniquement) en une version supportant PostgreSQL de manière native.
Contact Assietou DIAGNE :
- • Email: siatou.sissi@gmail.com
- • LinkedIn: Assiétou Diagne
- • Organisation: ANSD Sénégal
Table des Matières
- Introduction
- Contexte et Problématique
- Vue d'Ensemble des Modifications
- Étape 1: Intégration du Driver pdo_pgsql
- Étape 2: Mise à Jour de la Base de Données
- Étape 3: Transformation des Scripts
- Étape 4: Génération des Schémas PostgreSQL
- Reproduire sur CSWeb Vanilla
- Références Techniques
Introduction
Objectif Transformer CSWeb vanilla (MySQL only) en une version supportant PostgreSQL pour permettre :
Breakout vers PostgreSQL (meilleur pour analytics) Support multi-SGBD (PostgreSQL, MySQL, SQL Server) Architecture flexible (local/remote) Performance améliorée (indexation PostgreSQL)
Auteur Ce travail technique a été réalisé par Assietou DIAGNE (ANSD, Sénégal) dans le cadre du projet RGPH5 (Recensement Général de la Population et de l'Habitat du Sénégal).
Contexte et Problématique
CSWeb Vanilla (Avant)
Limites :
Support MySQL uniquement pour le breakout Pas de driver PostgreSQL intégré
Code hardcodé pour MySQL (MySQLDictionarySchemaGenerator)
Fonctions SQL spécifiques MySQL (incompatibles PostgreSQL)
Architecture :
CSWeb Vanilla (Setup.php)
Base Métadonnées: MySQL (SEUL)
Base Breakout: MySQL (SEUL)
CSWeb Community v2.0 (Après Transformation)
Améliorations :
Support PostgreSQL natif Support MySQL (rétrocompatible) Support SQL Server (Microsoft) Architecture flexible (local/remote) Breakout sélectif par dictionnaire
Architecture :
CSWeb Community v2.0 (Transformé)
Base Métadonnées: MySQL (local)
Base Breakout: PostgreSQL/MySQL/SQLServer
(local OU remote)
Vue d'Ensemble des Modifications
Fichiers PHP Modifiés (Core)
| Fichier | Modifications | Impact |
|---|---|---|
DictionarySchemaHelper.php | Ajout support pdo_pgsql | Driver PostgreSQL disponible |
DataSettings.php | Détection type DB breakout | Configuration multi-SGBD |
MapDataRepository.php | Gestion connexion PostgreSQL | Repository flexible |
MySQLDictionarySchemaGenerator.php | Transformation complète | Génération schéma PostgreSQL |
Transformations Clés
cleanDictionarySchema()- Nettoyage schéma avant breakoutcreateDictionarySchema()- Création schéma PostgreSQLgenerateDictionary()- Génération structure dictionnairecreateDefaultTables()- Création tablescases,notes,jobs,cspro_meta
Étape 1: Intégration du Driver pdo_pgsql
A. Modification de DictionarySchemaHelper.php
Objectif : Ajouter le driver PostgreSQL aux drivers disponibles.
Code Avant (MySQL uniquement)
class DictionarySchemaHelper
{
// Uniquement MySQL supporté
private $mysqlConnection;
public function __construct()
{
// Hardcoded MySQL
$this->mysqlConnection = new PDO('mysql:host=...');
}
}Code Après (Multi-SGBD)
class DictionarySchemaHelper
{
private $connection;
private $dbType; // 'mysql', 'pgsql', 'sqlsrv'
public function __construct($dbType = 'mysql')
{
$this->dbType = $dbType;
switch ($dbType) {
case 'pgsql':
$this->connection = new PDO('pgsql:host=...'); // PostgreSQL break;
case 'mysql':
$this->connection = new PDO('mysql:host=...');
break;
case 'sqlsrv':
$this->connection = new PDO('sqlsrv:Server=...');
break;
}
}
}B. Modification de DataSettings.php
Objectif : Lire la configuration du SGBD de breakout depuis .env.
Ajout Variables d'Environnement
// Dans DataSettings.php
public function getBreakoutDbType(): string
{
return $_ENV['BREAKOUT_DB_TYPE'] ?? 'mysql'; // Par défaut: mysql
}
public function getBreakoutDbHost(): string
{
return $_ENV['BREAKOUT_DB_HOST'] ?? 'localhost';
}
public function getBreakoutDbPort(): int
{
$type = $this->getBreakoutDbType();
// Ports par défaut selon SGBD
$defaultPorts = [
'mysql' => 3306,
'pgsql' => 5432,
'sqlsrv' => 1433,
];
return $_ENV['BREAKOUT_DB_PORT'] ?? $defaultPorts[$type];
}Fichier .env Correspondant
# Configuration Breakout Database
BREAKOUT_DB_TYPE=pgsql # mysql|pgsql|sqlsrv
BREAKOUT_DB_HOST=csweb_postgres
BREAKOUT_DB_PORT=5432
BREAKOUT_DB_NAME=csweb_analytics
BREAKOUT_DB_USER=csweb_user
BREAKOUT_DB_PASSWORD=VOTRE_PASSWORD
BREAKOUT_DB_SCHEMA=public # Schéma PostgreSQL (optionnel)C. Modification de MapDataRepository.php
Objectif : Utiliser la connexion PostgreSQL au lieu de MySQL pour le repository.
Code Transformé
class MapDataRepository
{
private $connection;
private $dbType;
public function __construct(DataSettings $settings)
{
$this->dbType = $settings->getBreakoutDbType();
// Créer connexion selon type DB
$dsn = $this->buildDsn($settings);
$this->connection = new PDO(
$dsn,
$settings->getBreakoutDbUser(),
$settings->getBreakoutDbPassword()
);
}
private function buildDsn(DataSettings $settings): string
{
switch ($this->dbType) {
case 'pgsql':
return sprintf(
'pgsql:host=%s;port=%d;dbname=%s',
$settings->getBreakoutDbHost(),
$settings->getBreakoutDbPort(),
$settings->getBreakoutDbName()
);
case 'mysql':
return sprintf('mysql:host=%s;port=%d;dbname=%s', ...);
case 'sqlsrv':
return sprintf('sqlsrv:Server=%s,%d;Database=%s', ...);
}
}
}Étape 2: Mise à Jour de la Base de Données
A. Transformation cleanDictionarySchema()
Objectif : Nettoyer le schéma PostgreSQL avant un nouveau breakout (supprimer tables existantes).
Code Avant (MySQL)
private function cleanDictionarySchema() {
try {
$tables = $this->conn->getSchemaManager()->listTables();
if ((is_countable($tables) ? count($tables) : 0) > 0) {
$this->conn->prepare("SET FOREIGN_KEY_CHECKS = 0;")->execute(); // MySQL specific foreach ($tables as $table) {
$sql = 'DROP TABLE ' . $table->getName(); // MySQL syntax
$this->conn->prepare($sql)->execute();
}
$this->conn->prepare("SET FOREIGN_KEY_CHECKS = 1;")->execute();
}
} catch (\Exception $e) {
throw $e;
}
}Code Après (PostgreSQL Compatible)
private function cleanDictionarySchema() {
try {
$tables = $this->conn->getSchemaManager()->listTables();
if (count($tables) > 0) {
// PostgreSQL: Pas de FOREIGN_KEY_CHECKS, utiliser CASCADE
// var_dump(count($tables)); die;
foreach ($tables as $table) {
// DROP TABLE avec CASCADE pour PostgreSQL
$sql = 'DROP TABLE "' . $table->getName() . '" CASCADE';
// Optionnel: Désactiver triggers temporairement
// $this->conn->prepare('ALTER TABLE "' . $table->getName() . '" DISABLE TRIGGER ALL;')->execute();
$this->conn->prepare($sql)->execute();
// $this->conn->prepare('ALTER TABLE "' . $table->getName() . '" ENABLE TRIGGER ALL;')->execute();
}
}
} catch (\Exception $e) {
$strMsg = "Failed deleting tables from database: " . $this->connectionParams['dbname'] . " while processing Dictionary: " . $this->dictionaryName;
$this->logger->error($strMsg, ["context" => (string) $e]);
throw $e;
}
}Différences Clés :
| MySQL | PostgreSQL |
|---|---|
SET FOREIGN_KEY_CHECKS = 0; | Pas nécessaire, utiliser CASCADE |
DROP TABLE table_name | DROP TABLE "table_name" CASCADE |
| Noms sans guillemets | Noms entre guillemets doubles " |
B. Transformation createDictionarySchema()
Objectif : Insérer les métadonnées du dictionnaire dans cspro_meta (table commune).
Code Avant
private function createDictionarySchema($processCasesOptions) {
$bind = [];
try {
$dictionarySchema = new MySQLDictionarySchemaGenerator($this->logger);
$processCasesOptions = $this->getProcessCaseOptions();
$schema = $dictionarySchema->generateDictionary($this->dictionary, $processCasesOptions);
$dictionarySQL = $schema->toSql($this->conn->getDatabasePlatform());
$dictionarySQL = implode(";" . PHP_EOL, $dictionarySQL);
$this->logger->debug("writing schema SQL " . $dictionarySQL);
$this->conn->prepare($dictionarySQL)->execute();
//insert into cspro_meta dictionary_information
$dictionaryVersion = $this->dictionary->getVersion();
$stm = "SELECT modified_time, `dictionary_full_content` FROM cspro_dictionaries` ";
$stm .= " WHERE `dictionary_name` = '" . $this->dictionaryName . "'";
// ... insertion dans cspro_meta
}
}Code Après (PostgreSQL)
private function createDictionarySchema($processCasesOptions) {
$bind = [];
try {
$dictionarySchema = new MySQLDictionarySchemaGenerator($this->logger);
$processCasesOptions = $this->getProcessCaseOptions();
$schema = $dictionarySchema->generateDictionary($this->dictionary, $processCasesOptions);
$dictionarySQL = $schema->toSql($this->conn->getDatabasePlatform());
$explodedDictionarySQL = implode(";" . PHP_EOL, $dictionarySQL);
$this->logger->debug("writing schema SQL " . $explodedDictionarySQL);
// PostgreSQL: Exécuter chaque statement séparément foreach($dictionarySQL AS $oneDictionarySQL){
$this->conn->prepare($oneDictionarySQL)->execute();
}
//insert into cspro_meta dictionary_information
$dictionaryVersion = $this->dictionary->getVersion();
//Récupération du label du dictionnaire pour synchronisation
$dictionaryLabel = str_replace(" ", "_", str_replace("_DICT", "", $this->dictionary->getName()));
$stm = "SELECT modified_time, `dictionary_full_content` FROM cspro_dictionaries` "
. " WHERE `dictionary_name` = '" . $this->dictionaryName . "'";
$result = $this->pdo->fetchOne($stm);
if ($result) {
$stm = "INSERT INTO `cspro_meta`(`cspro_version`, `dictionary`, `source_modified_time`) "
. " VALUES (:version, :dictionary, :source_modified_time)";
$bind['version'] = $dictionaryVersion;
$bind['dictionary'] = $result['dictionary_full_content'];
$bind['source_modified_time'] = $result['modified_time'];
$stmt = $this->conn->executeUpdate($stm, $bind);
}
} catch (\Exception $e) {
// ... error handling
}
}Amélioration PostgreSQL :
foreach($dictionarySQL AS $oneDictionarySQL){
$this->conn->prepare($oneDictionarySQL)->execute();
}Pourquoi ? PostgreSQL n'accepte pas les multi-statements séparés par ; dans un seul execute(). Il faut exécuter chaque statement individuellement.
Étape 3: Transformation des Scripts
A. Transformation generateDictionary()
Objectif : Générer le schéma complet d'un dictionnaire (tables hierarchiques).
Code Avant (MySQL)
public function generateDictionary(Dictionary $dictionary, $processCasesOptions) {
DictionarySchemaHelper::updateProcessCasesOptions($dictionary, $processCasesOptions);
$this->schema = new Schema();
$this->createDefaultTables();
$parentLevel = null;
//TODO check for Charset | Collation | comment for ($iLevel = 0; $iLevel < (is_countable($dictionary->getLevels()) ? count($dictionary->getLevels()) : 0); $iLevel++) {
$level = $dictionary->getLevels()[$iLevel];
$level->setLevelNumber($iLevel);
$this->generateLevel($level, $parentLevel);
$parentLevel = $dictionary->getLevels()[$iLevel];
}
return $this->schema;
}Code Après (PostgreSQL Compatible)
public function generateDictionary(Dictionary $dictionary, $processCasesOptions) {
DictionarySchemaHelper::updateProcessCasesOptions($dictionary, $processCasesOptions);
//Récupérer le label du dictionnaire pour synchronisation données
$this->nomSchema = str_replace(" ", "_",
str_replace("_DICT", "", $dictionary->getName()));
$this->schema = new Schema();
$this->createDefaultTables();
$parentLevel = null;
//TODO check for Charset | Collation | comment for ($iLevel = 0; $iLevel < (is_countable($dictionary->getLevels()) ?
count($dictionary->getLevels()) : 0); $iLevel++) {
$level = $dictionary->getLevels()[$iLevel];
$level->setLevelNumber($iLevel);
$this->generateLevel($level, $parentLevel);
$parentLevel = $dictionary->getLevels()[$iLevel];
}
return $this->schema;
}Clé : Ajout de $this->nomSchema pour stocker le nom du schéma PostgreSQL (basé sur le label du dictionnaire).
B. Transformation createDefaultTables()
Objectif : Créer les 4 tables système : cases, notes, cspro_jobs, cspro_meta.
Structure Complète (PostgreSQL)
Table cases
public function createDefaultTables()
{
//cases
/* "CREATE TABLE cases ("
"id TEXT NOT NULL,"
"`key` TEXT NOT NULL,"
"label TEXT,"
"questionnaire TEXT NOT NULL,"
"last_modified_revision INTEGER NOT NULL,"
"deleted INTEGER NOT NULL DEFAULT 0,"
"verified INTEGER NOT NULL DEFAULT 0,"
"partial_save_mode TEXT NULL,"
"partial_save_field_name TEXT NULL,"
"partial_save_level_key TEXT NULL,"
"partial_save_record_occurrence INTEGER NULL,"
"partial_save_item_occurrence INTEGER NULL,"
"partial_save_subitem_occurrence INTEGER NULL,"
"FOREIGN KEY(last_modified_revision) REFERENCES file_revisions(id)"
");\\n" */
$casesTable = $this->schema->createTable($this->nomSchema."_cases");
$casesTable->addColumn("id", "text", ["notnull" => true]);
$casesTable->addColumn("key", "text", ["notnull" => true]);
$casesTable->addColumn("label", "text");
$casesTable->addColumn("questionnaire", "text", ["notnull" => false, "default" => null]);
$casesTable->addColumn("last_modified_revision", "integer", ["notnull" => true]);
$casesTable->addColumn("deleted", "integer", ["notnull" => true, "default" => 0]);
$casesTable->addColumn("verified", "integer", ["notnull" => true, "default" => 0]);
$casesTable->addColumn("partial_save_mode", "text", ["notnull" => false, "default" => null]);
$casesTable->addColumn("partial_save_field_name", "text", ["notnull" => false, "default" => null]);
$casesTable->addColumn("partial_save_level_key", "text", ["notnull" => false, "default" => null]);
$casesTable->addColumn("partial_save_record_occurrence", "integer", ["notnull" => false, "default" => null]);
$casesTable->addColumn("partial_save_item_occurrence", "integer", ["notnull" => false, "default" => null]);
$casesTable->addColumn("partial_save_subitem_occurrence", "integer", ["notnull" => false, "default" => null]);
$casesTable->addUniqueIndex(["`id`"], null, ["lengths" => [191]]);
$casesTable->addIndex(["deleted"]);
//notes
// ...
}Différences Clés MySQL vs PostgreSQL :
| MySQL | PostgreSQL |
|---|---|
Backticks `column` | Guillemets doubles "column" |
VARCHAR(191) | TEXT (pas de limite) |
AUTO_INCREMENT | SERIAL ou IDENTITY |
ENGINE=InnoDB | Pas nécessaire (défaut) |
Table notes
//notes
/* "CREATE TABLE notes ("
"case_id TEXT NOT NULL,"
"field_name TEXT NOT NULL,"
"level_key TEXT NOT NULL,"
"record_occurrence INTEGER NOT NULL,"
"item_occurrence INTEGER NOT NULL,"
"subitem_occurrence INTEGER NOT NULL,"
"content TEXT NOT NULL,"
"operator_id TEXT NOT NULL,"
"modified_time INTEGER NOT NULL,"
"FOREIGN KEY(case_id) REFERENCES cases(id)"
");\\n"
"CREATE INDEX `notes-case-id` ON notes(case_id);"; */
$notesTable = $this->schema->createTable($this->nomSchema."_notes");
$notesTable->addColumn("case_id", "text", ["notnull" => true]);
$notesTable->addColumn("field_name", "text", ["notnull" => true]);
$notesTable->addColumn("level_key", "text", ["notnull" => true]);
$notesTable->addColumn("record_occurrence", "integer", ["notnull" => true]);
$notesTable->addColumn("item_occurrence", "integer", ["notnull" => true]);
$notesTable->addColumn("subitem_occurrence", "integer", ["notnull" => true]);
$notesTable->addColumn("content", "text", ["notnull" => true]);
$notesTable->addColumn("operator_id", "text", ["notnull" => true]);
$notesTable->addColumn("`modified_time`", "datetime",
['columnDefinition' => 'timestamp default current_timestamp']);
$notesTable->addIndex(["case_id"], null, [], ["lengths" => [191]]);
//DBAL has issues with creating foreign key constraint on text columns with lengths.
//not adding for now, if needed add it in the future
// $notesTable->addForeignKeyConstraint($this->quoteString('cases'),
// array($this->quoteString('case_id')),
// array($this->quoteString('id')),
// array("lengths" => array(191,191)), 'notes_cases_fk');Table cspro_jobs
/* CREATE TABLE IF NOT EXISTS `cspro_jobs` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`startCaseId` int unsigned NOT NULL,
`startRevision` int unsigned NOT NULL,
`endCaseId` int unsigned NOT NULL,
`endRevision` int unsigned NOT NULL,
`casesProcessed` int unsigned NULL,
`created_time` timestamp NOT NULL NULL DEFAULT CURRENT_TIMESTAMP,
`modified_time` timestamp NOT NULL NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
*/
$jobsTable = $this->schema->createTable($this->nomSchema."_cspro_jobs");
$jobsTable->addColumn("`id`", "integer", ["unsigned" => true, "notnull" => true, "autoincrement" => true]);
$jobsTable->addColumn("`start_caseid`", "integer", ["unsigned" => true, "notnull" => true]);
$jobsTable->addColumn("`start_revision`", "integer", ["unsigned" => true, "notnull" => true]);
$jobsTable->addColumn("`end_caseid`", "integer", ["unsigned" => true, "notnull" => true]);
$jobsTable->addColumn("`end_revision`", "integer", ["unsigned" => true, "notnull" => true]);
$jobsTable->addColumn("`cases_to_process`", "integer", ["unsigned" => true, "notnull" => false, "default" => null]);
$jobsTable->addColumn("`cases_processed`", "integer", ["unsigned" => true, "notnull" => false, "default" => null]);
$jobsTable->addColumn("`status`", "integer", ["unsigned" => true, "notnull" => true, "default" => 0]);
$jobsTable->addColumn("`created_time`", "datetime",
['columnDefinition' => 'timestamp default current_timestamp']);
$jobsTable->addColumn("`modified_time`", "datetime",
['columnDefinition' => 'timestamp default current_timestamp on update current_timestamp']);
$jobsTable->setPrimaryKey(["`id`"]);Table cspro_meta
//Create meta table
$metaTable = $this->schema->createTable($this->nomSchema."_cspro_meta");
$metaTable->addColumn("`id`", "integer", ["unsigned" => true, "notnull" => true, "autoincrement" => true]);
$metaTable->addColumn("`cspro_version`", "text", ["notnull" => true]);
$metaTable->addColumn("`dictionary`", "text", ["notnull" => true]);
$metaTable->addColumn("`source_modified_time`", "datetime", ["default" => null]);
$metaTable->addColumn("`created_time`", "datetime",
['columnDefinition' => 'timestamp default current_timestamp']);
$metaTable->addColumn("`modified_time`", "datetime",
['columnDefinition' => 'timestamp default current_timestamp on update current_timestamp']);
$metaTable->setPrimaryKey(["`id`"]);Étape 4: Génération des Schémas PostgreSQL
Nomenclature des Tables
Pattern :
{nom_schema}_{table}Exemples :
- Dictionnaire :
EVAL_PRODUCTEURS_USAID - Schéma :
eval_producteurs(minuscules,_DICTsupprimé) - Tables générées :
eval_producteurs_caseseval_producteurs_noteseval_producteurs_cspro_jobseval_producteurs_cspro_metaeval_producteurs_producteurs(level 1)eval_producteurs_observations(level 2)eval_producteurs_photos(level 3)
Reproduire sur CSWeb Vanilla
Prérequis
- CSWeb vanilla installé (version 7.7+)
- PostgreSQL 12+ installé et accessible
- PHP 8.0+ avec extension
pdo_pgsqlactivée - Composer installé
- Accès SSH au serveur CSWeb
Étapes de Transformation
1. Installer l'Extension pdo_pgsql
Sur Ubuntu/Debian :
# Installer pdo_pgsql
sudo apt-get update
sudo apt-get install php8.1-pgsql
# Vérifier
php -m | grep pdo_pgsql
# Sortie attendue: pdo_pgsql
# Redémarrer Apache/PHP-FPM
sudo systemctl restart apache2
# ou
sudo systemctl restart php8.1-fpmSur Docker (Dockerfile) :
FROM php:8.1-apache
# Installer pdo_pgsql
RUN apt-get update && apt-get install -y libpq-dev \\
&& docker-php-ext-install pdo_pgsql pgsql
# Vérifier
RUN php -m | grep pdo_pgsql2. Modifier les Fichiers PHP (Selon Document PDF)
Fichier 1 : src/AppBundle/Service/DictionarySchemaHelper.php
Ajouter le support pdo_pgsql comme montré dans Étape 1.
Fichier 2 : src/AppBundle/Service/DataSettings.php
Ajouter les getters pour configuration breakout PostgreSQL.
Fichier 3 : src/AppBundle/Repository/MapDataRepository.php
Modifier le constructor pour accepter PostgreSQL.
Fichier 4 : src/AppBundle/CSPro/DictionarySchemaGenerator/MySQLDictionarySchemaGenerator.php
C'est le fichier le plus critique. Appliquer toutes les transformations de Étape 2 et Étape 3.
3. Configurer .env pour PostgreSQL
# Créer/Éditer .env
vim /var/www/csweb/.env
# Ajouter configuration breakout
BREAKOUT_DB_TYPE=pgsql
BREAKOUT_DB_HOST=localhost
BREAKOUT_DB_PORT=5432
BREAKOUT_DB_NAME=csweb_analytics
BREAKOUT_DB_USER=csweb_user
BREAKOUT_DB_PASSWORD=STRONG_PASSWORD_HERE
BREAKOUT_DB_SCHEMA=public4. Créer la Base PostgreSQL
# Se connecter à PostgreSQL
sudo -u postgres psql
# Créer database
CREATE DATABASE csweb_analytics;
# Créer user
CREATE USER csweb_user WITH PASSWORD 'STRONG_PASSWORD_HERE';
# Accorder privilèges
GRANT ALL PRIVILEGES ON DATABASE csweb_analytics TO csweb_user;
# Sortir
\\q5. Tester le Breakout PostgreSQL
# Se connecter au container/serveur CSWeb
cd /var/www/csweb
# Lancer breakout vers PostgreSQL
php bin/console csweb:process-cases-by-dict EVAL_PRODUCTEURS_USAID
# Vérifier les tables créées
psql -U csweb_user -d csweb_analytics -c "\\dt"
# Résultat attendu:
# eval_producteurs_cases
# eval_producteurs_notes
# eval_producteurs_producteurs
# eval_producteurs_observations
# ...6. Vérifier les Données
-- Compter les cases
SELECT COUNT(*) FROM eval_producteurs_cases;
-- Voir échantillon producteurs
SELECT * FROM eval_producteurs_producteurs LIMIT 10;
-- Vérifier les métadonnées
SELECT * FROM eval_producteurs_cspro_meta;Références Techniques
Document Source
DOC-20251121-WA0004.pdf (48 pages) Auteur : Assietou DIAGNE (ANSD, Sénégal) Date : 21 Novembre 2025
Code PHP Complet Le code complet de transformation est disponible dans le repository CSWeb Community v2.0 :
# Cloner le repository
git clone https://github.com/BOUNADRAME/csweb-community.git
# Fichiers clés transformés
src/AppBundle/CSPro/DictionarySchemaGenerator/MySQLDictionarySchemaGenerator.php
src/AppBundle/Service/DictionarySchemaHelper.php
src/AppBundle/Service/DataSettings.php
src/AppBundle/Repository/MapDataRepository.phpRessources Additionnelles
- PostgreSQL Documentation : https://www.postgresql.org/docs/ (opens in a new tab)
- Doctrine DBAL (Schema Manager) : https://www.doctrine-project.org/projects/dbal.html (opens in a new tab)
- CSPro Official : https://www.census.gov/data/software/cspro.html (opens in a new tab)
Contact & Support
Questions Techniques Pour toute question technique sur la transformation PostgreSQL :
Assietou DIAGNE Email : siatou.sissi@gmail.com LinkedIn : Assiétou Diagne (opens in a new tab) Organisation : ANSD (Sénégal)
Contribution Vous avez amélioré le code ou trouvé des bugs ?
- Fork le repository CSWeb Community
- Créer une branche (
git checkout -b feature/amelioration-pgsql) - Commit vos changements
- Push et créer une Pull Request
Repository GitHub (opens in a new tab)
Conclusion
Impact de cette Transformation
Le travail technique d'Assietou DIAGNE a permis de :
- Démocratiser PostgreSQL pour les instituts statistiques africains
- Améliorer les performances de breakout (10x plus rapide sur grands volumes)
- Rendre possible l'analytics moderne (Power BI, Tableau, Metabase)
- Poser les bases de l'architecture flexible CSWeb Community v2.0
Ce guide est un hommage technique au travail d'Assietou. Merci pour cette contribution majeure !
Prochaines Étapes :
Documentation créée par Bouna DRAME basée sur le travail technique d'Assietou DIAGNE © 2026