ImportBundle: L'import facile sous Symfony

L'ImportBundle peut être utilisé pour importer vos fichiers CSV et transformer chaque ligne du fichier en entité dans Symfony. Il est simple à installer, simple à configurer et surtout extensible.
Vous pourrez facilement ajouter d'autres readers qui vous permettront d'importer des fichiers XML, Excel ou autres.

Lien GitHub :

https://github.com/ClickAndMortar/ImportBundle

Installation 

Ajoutez le bundle à votre composer.json :

"require": {
            ...
            "clickandmortar/import-bundle": "^1.0"
            ...
        }

Ou plus simplement :

composer require "clickandmortar/import-bundle" "^1.0"

Et enfin chargez le dans votre fichier AppKernel.php :

$bundles = array(
                    ...
                    new ClickAndMortar\ImportBundle\ClickAndMortarImportBundle(),
                );

Configuration

Vous pouvez mettre en place plusieurs imports pour plusieurs entités directement dans le fichier de configuration de votre projet (config.yml). Voici un exemple de configuration pour l'import d'utilisateurs :

click_and_mortar_import:
          entities:
            customer_from_pim: # Le nom de votre import
              model: Acme\DemoBundle\Entity\Customer
              repository: AcmeDemoBundle:Customer
              unique_key: id
              mappings:
                id: "ID"
                name: "Name_For_Customer"
                firstname: "FirstName"
                gender: "Sex"
                age: "Age"
        

Voici une explication sur les différentes options possibles :

Type d'option Obligatoire Exemple Commentaire
model Oui Acme\DemoBundle\Entity\Customer C'est la classe qui correspond à l'entité que vous souhaitez mapper
repository Oui AcmeDemoBundle:Customer Le repository de votre entité
unique_key Non id La clé unique pour l'import (pour éviter les doublons et permettre la mise à jour d'une entité avec plusieurs imports successifs)
only_update Non false true: Mettre à jour les entités uniquement / false: Créer et mettre à jour
import_helper_service Non acme.demo.import_helper.my_import_helper Vous pouvez ajouter ici l'identifiant d'un service pour étendre votre import et modifier les propriétés de votre entité avant l'enregistrement (nous allons voir celà juste en dessous)

Extension

Compléter les données

Un import simple des données c'est bien, mais on peut avoir besoin parfois d'effectuer des opérations sur les données avant de les enregistrer dans la base de données ou de créer de nouvelles propriétés en fonction d'autres. L'option import_helper_service vous permet de faire tout ça.

Commencez par créer un dossier ImportHelper dans votre bundle custom et créez le service suivant :

<?php
        
        namespace MyProject\MyCustomImportBundle\ImportHelper;
        
        use ClickAndMortar\ImportBundle\ImportHelper\ImportHelperInterface;
        use MyProject\MyCustomImportBundle\Entity\Customer;
        
        /**
         * Class MyImportHelper
         *
         * @package MyProject\MyCustomImportBundle\MyImportHelper
         */
        class MyImportHelper implements ImportHelperInterface
        {
            /**
             * Complete your $entity with $data from import
             *
             * @param Customer $entity
             * @param array $data
             * @param array $errors
             */
            public function completeData(&$entity, array $data, array &$errors)
            {
                // Call all necessary methods here to update your $entity
            }
        }
        

Et déclarez le service dans votre fichier services.yml :

parameters:
          # Import helpers
          myproject.import_helpers.my_custom_import_helper.class: MyProject\MyCustomImportBundle\ImportHelper\MyImportHelper
        
        services:
          # Import helpers
          myproject.import_helpers.my_custom_import_helper:
            class: %myproject.import_helpers.my_custom_import_helper.class%

La méthode completeData sera appelée après le mapping classique pour mettre à jour d'autres propriétés sur votre entité via le tableau des données $data. Si une erreur a lieu, vous pouvez la stocker dans le tableau $errors, elle remontera à la fin de l'import.

Du CSV ? Mais moi je veux importer un fichier XML !

Pas de soucis, il faut ajouter un reader qui correspond à vos besoins (n'hésitez d'ailleurs pas à nous soumettre vos propres readers pour qu'on les intégrer dans le projet). Ajoutez une classe MyCustomXmlReader.php dans le dossier Reader/Readers de votre bundle :

<?php
        
        namespace MyBundle\MyCustomImportBundle\Reader\Readers;
        
        use ClickAndMortar\ImportBundle\Reader\AbstractReader;
        
        /**
         * Class MyCustomXmlReader
         *
         * @package MyBundle\MyCustomImportBundle\Reader\Readers
         */
        class MyCustomXmlReader extends AbstractReader
        {
            /**
             * Read my custom XML file and return data array
             *
             * @param string $path
             *
             * @return array
             */
            public function read($path)
            {
                $data = array();
        
                ...
        
                return $data;
            }
        
            /**
             * Support only xml type
             *
             * @param string $type
             *
             * @return bool
             */
            public function support($type)
            {
                return $type == 'xml';
            }
        }

Et ajoutez ce reader avec le bon tag dans votre fichier services.yml :

parameters:
          myproject.my_custom_import_bundle.reader.my_custom_xml_reader.class: MyBundle\MyCustomImportBundle\Reader\Readers\MyCustomXmlReader
        
        services:
          myproject.my_custom_import_bundle.reader.my_custom_xml_reader:
            class: %myproject.my_custom_import_bundle.reader.my_custom_xml_reader.class%
            tags:
              - { name: clickandmortar.import.reader }

Le but est ensuite d'alimenter le tableau $data dans la méthode read via la lecture de votre fichier XML.

Utilisation

Et le moment de l'utilisation est enfin arrivé ! Et bien l'import se fait ensuite simplement via la ligne de commande suivante :

php app/console candm:import /path/of/your/file/customers.csv customer_from_pim --delete-after-import

L'option --delete-after-import est facultative, elle vous permet de supprimer le fichier du dossier après l'import. Ajoutez la ligne dans votre crontab et vous avez un système automatisé d'import complet sur Symfony !