Commit 4fb9e346 authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

Ajout d'un README

parent 77f10134
Loading
Loading
Loading
Loading
+341 −2
Changes for README.md: 341 added lines, 2 removed lines.
Original line number Diff line number Diff line
# unicaen/exemple
Module unicaen/db-import-exemple
================================

Ce module rassemble des exemples d'utilisation de la bibliothèque `unicaen/db-import`.

<!-- TOC -->
* [Module unicaen/db-import-exemple](#module-unicaendb-import-exemple)
  * [Installation, configuration and co](#installation-configuration-and-co)
    * [Installation](#installation)
    * [Configuration](#configuration)
    * [Démarrage des bases de données](#démarrage-des-bases-de-données)
  * [Import depuis une autre base de données](#import-depuis-une-autre-base-de-données)
  * [Import de données issues d'une API](#import-de-données-issues-dune-api)
  * [Synchronisation au sein d'une même base de données](#synchronisation-au-sein-dune-même-base-de-données)
  * [Synchronisation depuis une autre base de données](#synchronisation-depuis-une-autre-base-de-données)
<!-- TOC -->



Installation, configuration and co
------------------------------------------------------------------------------------------------------------------------

### Installation

   ```bash
   composer require unicaen/db-import-exemple
   ```

### Configuration

  - Ajouter ces 2 services Docker (bases de données) dans le `docker-compose.yml` de votre appli, 
    en prenant soin de les placer dans le même "network" que votre appli :

  ```
  db_destination:
    extends:
      file: vendor/unicaen/db-import-exemple/docker-compose.yml
      service: db_destination
    networks:
      - sygalnet  <----- à adapter

  db_source:
    extends:
      file: vendor/unicaen/db-import-exemple/docker-compose.yml
      service: db_source
    networks:
      - sygalnet  <----- à adapter
  ```

  - Regardez dans le [docker-compose.yml](docker-compose.yml) du module et décidez éventuellement de
    surcharger des choses. Exemple :

  ```
  db_destination:
    [...]
    volumes:
      - /tmp/unicaen-db-import-exemple/db_destination:/var/lib/postgresql/data

  db_source:
    [...]
    volumes:
      - /tmp/unicaen-db-import-exemple/db_source:/var/lib/postgresql/data
  ```

### Démarrage des bases de données

   ```bash
   docker compose up -d db_destination db_soure
   ```



Import depuis une autre base de données
------------------------------------------------------------------------------------------------------------------------

Dans de nombreux cas, on souhaite importer une table (ou une vue, ou un "select") de données provenant d'une autre
base que celle de destination.
Ce peut être utile par exemple pour disposer de données externes sans être impacté par une indisponibilité
de la base de données source (en cas de maintenance par exemple).

Les connexions Doctrine aux bases de données source et destination sont configurées dans la config commune 
[module.config.php](config/module.config.php) :

  ```php
    'doctrine' => [
        'connection' => [
            'orm_destination' => [
                //...
            ],
            'orm_source' => [
                //...
            ],
        ],
    ],
    'import' => [
        'connections' => [
            'db_destination' => 'doctrine.connection.orm_destination',
            'db_source'      => 'doctrine.connection.orm_source',
        ],
    ],
  ```

Le reste de la config pour cet exemple est dans [import_autre_bdd.config.php](config/exemples/import_autre_bdd.config.php).

Dans le menu "Exemple > Import/Synchro" puis sous-menu "Imports", vous trouverez l'import `exemple_import_pays`
dans la liste et ainsi accéder à sa fiche, le lancer et voir les logs d'exécution.

Le lancement en ligne de commande :
```bash
php vendor/bin/laminas unicaen:db-import:run-import --name "exemple_import_pays"
```

Dans les logs, vous verrez entre autres un truc du genre :

    # insert :    249 enregistrement(s).




Import depuis une API
------------------------------------------------------------------------------------------------------------------------

Dans cet exemple, on souhaite importer les régions et départements français fournies par l'API geo.api.gouv.fr
(https://geo.api.gouv.fr/decoupage-administratif).

Dans la config commune [module.config.php](config/module.config.php) est notamment configurée la connexion
à l'API :

  ```php
      'import' => [
          'connections' => [
              'api_geo' => [
                  'url' => 'https://geo.api.gouv.fr',
  ```

Les 2 imports `exemple_import_api_region` et `exemple_import_api_departement` sont configurés dans le fichier de config 
[import_api.config.php](config/exemples/import_api.config.php).

Dans le menu "Exemple > Import/Synchro" puis sous-menu "Imports" de votre appli, vous trouverez ces 2 imports
dans la liste et pourrez accéder à leur fiche détaillée (caractéristiques, bouton de lancement, logs d'exécution).

L'import des régions se fait dans la table destination `region`, mais notez que l'import `exemple_import_api_departement` 
se fait dans une table destination `tmp_departement` qui sera utilisée dans l'exemple de synchro au sein d'une même 
base (ci-après).

Pour les lancer en ligne de commande :
```bash
php vendor/bin/laminas unicaen:db-import:run-import --name "exemple_import_api_region"
php vendor/bin/laminas unicaen:db-import:run-import --name "exemple_import_api_departement"
```

Dans les logs du 1er import, vous verrez entre autres un truc du genre :

    # insert :    18 enregistrement(s).

Puis dans ceux du 2e :

    # insert :    101 enregistrement(s).




Synchronisation locale : au sein d'une même base de données
------------------------------------------------------------------------------------------------------------------------

L'intérêt de ce cas de figure n'est peut-être pas évident mais il fournit une solution lorsqu'on souhaite 
"mettre en forme" des données résultant d'un import préalable.

Pour cet exemple, vous devez au préalable lancer les imports des régions et départements présentés au paragraphe 
[Import de données issues d'une API](#import-de-données-issues-dune-api).

Les données de la table `tmp_departement`, qui tenait lieu de destination pour l'import des départements, vont être ici
reprises par une vue `src_departement` qui sera la source d'une synchro vers la table destination `departement`.
La raison d'être de la vue `src_departement` est de "calculer" les clés étrangères `region_id` à partir des `codeRegion` 
afin d'avoir une jointure `departement(region_id) => region(id)`.

Voici le script de la vue `src_departement` présente dans la base de données destination :

```sql
create view src_departement(id, source_id, code, nom, region_id) as
select null::text as id,
       src.id as source_id,
       tmp.code,
       tmp.nom,
       r.id as region_id
from tmp_departement tmp
       join source src on src.id = tmp.source_id
       join region r on r.code = tmp.code_region;
```

Remarque : une autre solution consisterait à ne pas créer de vue et à mettre directement le `select null::text as id...` 
dans le paramètre `'select'` de la config de la source (au lieu du paramètre `table`).

Dans le menu "Exemple > Import/Synchro" puis sous-menu "Imports" de votre appli, vous trouverez ces 2 imports
dans la liste et pourrez accéder à leur fiche détaillée (caractéristiques, bouton de lancement, logs d'exécution).

Pour lancer la synchro en ligne de commande :
```bash
php vendor/bin/laminas unicaen:db-import:run-synchro --name "exemple_synchro_departement"
```

Dans les logs, vous verrez entre autres un truc du genre :

    # insert :    101 enregistrement(s).
    # update :    0 enregistrement(s).
    # undelete :  0 enregistrement(s).
    # delete :    0 enregistrement(s).

Pour illustrer complètement ce que fait une synchro, exécutez les instructions SQL suivantes dans la base de données 
destination : 

```sql
-- simule l'apparition d'un nouveau département
insert into tmp_departement(code, nom, code_region, source_id, histo_createur_id) select '2C', 'Corse-du-Centre', '94', s.id, 1 from source s where s.code = 'api_geo';
-- simule la modification d'un nom de département
update tmp_departement set nom = 'Loire-Bretonne' where code = '44';
-- simule la disparition d'un département
delete from tmp_departement where code = '06';
-- simule la réapparition d'un département
update departement set histo_destruction = now(), histo_destructeur_id = 1 where code = '01';
```

La vue `v_diff_departement`, générée lorsque vous avez lancé la synchro, signale les différences entre données source et 
données destination et les opérations nécessaires pour mettre la destination en phase avec la source. 
Voici ce qu'elle est sensée signaler après l'exécution des 4 instructions SQL précédentes :

| effectif | code | source\_id | operation | u\_source\_id | u\_nom | u\_region\_id | s\_source\_id | s\_nom | s\_region\_id | d\_source\_id | d\_nom | d\_region\_id |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| 1 | 2C | 2 | insert | 1 | 1 | 1 | 2 | Corse-du-Centre | 305 | null | null | null |
| 1 | 01 | 2 | undelete | 0 | 0 | 0 | 2 | Ain | 303 | 2 | Ain | 303 |
| 1 | 44 | 2 | update | 0 | 1 | 0 | 2 | Loire-Bretonne | 299 | 2 | Loire-Atlantique | 299 |
| 1 | 06 | 2 | delete | 1 | 1 | 1 | null | null | null | 2 | Alpes-Maritimes | 304 |

Vous avez aussi la version graphique du différentiel en vous rendant sur la fiche de la synchro en question 
(section "Différentiel").

Si vous relancez la synchro, les logs devraient signaler la réalisation des ces 4 opérations :

    # insert :    1 enregistrement(s).
    # update :    1 enregistrement(s).
    # undelete :  1 enregistrement(s).
    # delete :    1 enregistrement(s).

Et vous pourrez constater les conséquences dans la table destination `departement`.




Synchronisation à partir d'une autre base de données
------------------------------------------------------------------------------------------------------------------------

On est ici dans un type de synchro où les données sources sont dans une base de données différente de celle où 
résident la table destination.

Cette synchro "externe" fait d'abord appel au mécanisme d'import dans une table temporaire intermédiaire (d'où la 
présence du paramètre `intermediate_table`) et ensuite au mécanisme de synchro.

La config de la synchro `exemple_synchro_pays` se trouve dans le fichier [synchro_externe.config.php](config/exemples/synchro_externe.config.php).

Dans le menu "Exemple > Import/Synchro" puis sous-menu "Imports" de votre appli, vous trouverez cette synchro
dans la liste et pourrez accéder à leur fiche détaillée (caractéristiques, diff, bouton de lancement, logs d'exécution).

Pour la lancer en ligne de commande :
```bash
php vendor/bin/laminas unicaen:db-import:run-synchro --name "exemple_synchro_pays"
```

Dans les logs du 1er import, vous verrez entre autres un truc du genre :

    # insert :    249 enregistrement(s).
    # update :    0 enregistrement(s).
    # undelete :  0 enregistrement(s).
    # delete :    0 enregistrement(s).

**Attention : la table temporaire intermédiaire est systématiquement supprimée puis recréée au début du processus.** 
Si vous avez besoin d'utiliser cette table, c'est que ce type de synchronisation n'est pas approprié : mettez plutôt 
en place un import depuis l'autre base de données + une synchro au sein de la base destination.






Synchronisation à partir d'une API
------------------------------------------------------------------------------------------------------------------------

On est ici dans un type de synchro où les données sources sont obtenues en interrogeant une API.

Le principe est le même que pour la synchro à partir d'une autre base de données.

La config de la synchro `exemple_synchro_xxxxxxxxxxxxxx` se trouve dans le fichier xxxxxxxxxxxx.

Pour la lancer en ligne de commande :
```bash
php vendor/bin/laminas unicaen:db-import:run-synchro --name "exemple_synchro_xxxxxxxxxxxxxx"
```








PHP : import sans connexion + synchro
------------------------------------------------------------------------------------------------------------------------

Il est possible de créer/manipuler import et synchro en PHP.

Cet exemple illustre :
  - la création d'un import un peu particulier : les données source sont fournies manuellement sous la forme d'un 
    tableau (via une connexion de type "NoConnection") ;
  - le lancement de cet import pour enregistrer les données source dans la table destination ;
  - le lancement d'une synchro existante.

Voici les fichiers PHP :
    - [InscriptionAdministrativeProcess.php](src/Process/InscriptionAdministrativeProcess.php)
    - [InscriptionAdministrativeProcessFactory.php](src/Process/InscriptionAdministrativeProcessFactory.php)

**NB : cet exemple n'est pas exécutable.** 



Opérations sur les noms et valeurs de colonnes/attributs
------------------------------------------------------------------------------------------------------------------------

Il est possible d'agir sur les noms et les valeurs de colonnes/attributs des données source.
Il est aussi possible de créer des colonnes/attributs "calculés".

Le fichier [synchro_externe_columns_features.config.php](config/exemples/synchro_externe_columns_features.config.php)
contient un exemple de synchro nommée `exemple_synchro_pays_columns_features` dont la configuration de la source illustre :
  - la création d'une colonne calculée `libelle_calc` réalisant la concaténation des valeurs de 2 colonnes 
    (clé de config `computed_columns`) ;
  - la transformation des valeurs de la colonne `code_iso_alpha3` en lettres minuscules 
    (clé de config `column_value_filter`) ;
  - la spécification explicite du mapping de nommage par défaut des colonnes destination à partir des colonnes source
    (clé de config `column_name_filter`).

Conseil dans la cadre d'une source de type base de données : si vous avez beaucoup de manipulation à réaliser sur les
colonnes source, mieux vaut envisager d'écrire une vue de mise en forme directement dans la base source (si vous avez
la main sur celle-ci), ou alors mettre en place un import + une vue de mise en forme locale + une synchro locale.
Ce module rassemble des exemples d'utilisation de briques des bibliothèques Unicaen.
+0 −558

File deleted.

Preview size limit exceeded, changes collapsed.

+0 −52
Changes for config/unicaen-db-import.local.php: 0 added lines, 52 removed lines.
Original line number Diff line number Diff line
<?php
/**
 * Exemple de configuration locale du module unicaen/db-import.
 */

namespace Application;

use Doctrine\DBAL\Event\Listeners\OracleSessionInit;

return [
    'import' => [
        'connections' => [
            'default' => 'doctrine.connection.orm_default',
            'db_source' => 'doctrine.connection.orm_source',
            'api_geo' => [
                'url'      => 'https://geo.api.gouv.fr',
                'proxy'    => false,
                'verify'   => true,
                'user'     => null,
                'password' => null,
            ],
        ],
    ],

    'doctrine' => [
        'connection' => [
            'orm_default' => [
                'driverClass' => 'Doctrine\\DBAL\\Driver\\PDOPgSql\\Driver',
                'params' => [
                    'host'     => 'host.domain.fr',
                    'port'     => '5432',
                    'charset'  => 'utf8',
                    'user'     => '???',
                    'dbname'   => '???',
                    'password' => '???',
                ],
            ],
            'orm_source' => [
                'driverClass' => 'Doctrine\\DBAL\\Driver\\PDOPgSql\\Driver',
                'params'      => [
                    'host'     => 'host.domain.fr',
                    'port'     => '5432',
                    'charset'  => 'utf8',
                    'user'     => '???',
                    'dbname'   => '???',
                    'password' => '???',
                ],
            ],
        ],
    ],

];

docker/apache/000-default.conf

deleted100644 → 0
+0 −146
Changes for docker/apache/000-default.conf: 0 added lines, 146 removed lines.
Original line number Diff line number Diff line
<IfModule mod_ssl.c>
	<VirtualHost _default_:443>
		ServerAdmin webmaster@localhost

		DocumentRoot /var/www/html/public

        SetEnv APPLICATION_ENV "development"

        RewriteEngine On

        <Directory /var/www/html/public>
            DirectoryIndex index.php
            AllowOverride All
            Require all granted
        </Directory>

        Header always set Strict-Transport-Security "max-age=15768000; includeSubdomains;"

		# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
		# error, crit, alert, emerg.
		# It is also possible to configure the loglevel for particular
		# modules, e.g.
		#LogLevel info ssl:warn

		ErrorLog ${APACHE_LOG_DIR}/error.log
		CustomLog ${APACHE_LOG_DIR}/access.log combined

		# For most configuration files from conf-available/, which are
		# enabled or disabled at a global level, it is possible to
		# include a line for only one particular virtual host. For example the
		# following line enables the CGI configuration for this host only
		# after it has been globally disabled with "a2disconf".
		#Include conf-available/serve-cgi-bin.conf

		#   SSL Engine Switch:
		#   Enable/Disable SSL for this virtual host.
		SSLEngine on

		#   A self-signed (snakeoil) certificate can be created by installing
		#   the ssl-cert package. See
		#   /usr/share/doc/apache2/README.Debian.gz for more info.
		#   If both key and certificate are stored in the same file, only the
		#   SSLCertificateFile directive is needed.
		SSLCertificateFile	/etc/ssl/certs/ssl-cert-snakeoil.pem
		SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

		#   Server Certificate Chain:
		#   Point SSLCertificateChainFile at a file containing the
		#   concatenation of PEM encoded CA certificates which form the
		#   certificate chain for the server certificate. Alternatively
		#   the referenced file can be the same as SSLCertificateFile
		#   when the CA certificates are directly appended to the server
		#   certificate for convinience.
		#SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt

		#   Certificate Authority (CA):
		#   Set the CA certificate verification path where to find CA
		#   certificates for client authentication or alternatively one
		#   huge file containing all of them (file must be PEM encoded)
		#   Note: Inside SSLCACertificatePath you need hash symlinks
		#		 to point to the certificate files. Use the provided
		#		 Makefile to update the hash symlinks after changes.
		#SSLCACertificatePath /etc/ssl/certs/
		#SSLCACertificateFile /etc/apache2/ssl.crt/ca-bundle.crt

		#   Certificate Revocation Lists (CRL):
		#   Set the CA revocation path where to find CA CRLs for client
		#   authentication or alternatively one huge file containing all
		#   of them (file must be PEM encoded)
		#   Note: Inside SSLCARevocationPath you need hash symlinks
		#		 to point to the certificate files. Use the provided
		#		 Makefile to update the hash symlinks after changes.
		#SSLCARevocationPath /etc/apache2/ssl.crl/
		#SSLCARevocationFile /etc/apache2/ssl.crl/ca-bundle.crl

		#   Client Authentication (Type):
		#   Client certificate verification type and depth.  Types are
		#   none, optional, require and optional_no_ca.  Depth is a
		#   number which specifies how deeply to verify the certificate
		#   issuer chain before deciding the certificate is not valid.
		#SSLVerifyClient require
		#SSLVerifyDepth  10

		#   SSL Engine Options:
		#   Set various options for the SSL engine.
		#   o FakeBasicAuth:
		#	 Translate the client X.509 into a Basic Authorisation.  This means that
		#	 the standard Auth/DBMAuth methods can be used for access control.  The
		#	 user name is the `one line' version of the client's X.509 certificate.
		#	 Note that no password is obtained from the user. Every entry in the user
		#	 file needs this password: `xxj31ZMTZzkVA'.
		#   o ExportCertData:
		#	 This exports two additional environment variables: SSL_CLIENT_CERT and
		#	 SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
		#	 server (always existing) and the client (only existing when client
		#	 authentication is used). This can be used to import the certificates
		#	 into CGI scripts.
		#   o StdEnvVars:
		#	 This exports the standard SSL/TLS related `SSL_*' environment variables.
		#	 Per default this exportation is switched off for performance reasons,
		#	 because the extraction step is an expensive operation and is usually
		#	 useless for serving static content. So one usually enables the
		#	 exportation for CGI and SSI requests only.
		#   o OptRenegotiate:
		#	 This enables optimized SSL connection renegotiation handling when SSL
		#	 directives are used in per-directory context.
		#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
		<FilesMatch "\.(cgi|shtml|phtml|php)$">
				SSLOptions +StdEnvVars
		</FilesMatch>
		<Directory /usr/lib/cgi-bin>
				SSLOptions +StdEnvVars
		</Directory>

		#   SSL Protocol Adjustments:
		#   The safe and default but still SSL/TLS standard compliant shutdown
		#   approach is that mod_ssl sends the close notify alert but doesn't wait for
		#   the close notify alert from client. When you need a different shutdown
		#   approach you can use one of the following variables:
		#   o ssl-unclean-shutdown:
		#	 This forces an unclean shutdown when the connection is closed, i.e. no
		#	 SSL close notify alert is send or allowed to received.  This violates
		#	 the SSL/TLS standard but is needed for some brain-dead browsers. Use
		#	 this when you receive I/O errors because of the standard approach where
		#	 mod_ssl sends the close notify alert.
		#   o ssl-accurate-shutdown:
		#	 This forces an accurate shutdown when the connection is closed, i.e. a
		#	 SSL close notify alert is send and mod_ssl waits for the close notify
		#	 alert of the client. This is 100% SSL/TLS standard compliant, but in
		#	 practice often causes hanging connections with brain-dead browsers. Use
		#	 this only for browsers where you know that their SSL implementation
		#	 works correctly.
		#   Notice: Most problems of broken clients are also related to the HTTP
		#   keep-alive facility, so you usually additionally want to disable
		#   keep-alive for those clients, too. Use variable "nokeepalive" for this.
		#   Similarly, one has to force some clients to use HTTP/1.0 to workaround
		#   their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
		#   "force-response-1.0" for this.
		# BrowserMatch "MSIE [2-6]" \
		#		nokeepalive ssl-unclean-shutdown \
		#		downgrade-1.0 force-response-1.0

	</VirtualHost>
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
+0 −68

File deleted.

Preview size limit exceeded, changes collapsed.

Loading