web-dev-qa-db-fra.com

Exporter tout à partir de DataTables avec un traitement côté serveur?

J'ai des tables qui utilisent le traitement DataTables Server Side à afficher sur mon site Web. Je veux être en mesure d'exporter tout et d'exporter toutes les lignes, pas seulement les lignes affichées. Il y a plus de 60000 lignes et plus de 65 colonnes, cela doit donc être fait avec un traitement côté serveur.

J'ai essayé plusieurs choses, mais jusqu'à présent, rien n'a fonctionné.

J'ai essayé ceci:

{ extend: 'Excel',
    text: 'Export Current Page',
    exportOptions: {
        modifier: {
            page: 'current'
        }
    },
    customize: function (xlsx)
    {
        var sheet = xlsx.xl.worksheets['sheet1.xml'];
        $('row:first c', sheet).attr('s', '7');
    }
}

Qui n'a exporté que les lignes affichées sur la page.

J'ai essayé ceci:

{
    text: 'Export All to Excel',
    action: function (e, dt, button, config)
    {
        dt.one('preXhr', function (e, s, data)
        {
            data.length = -1;
        }).one('draw', function (e, settings, json, xhr)
        {
            var excelButtonConfig = $.fn.DataTable.ext.buttons.excelHtml5;
            var addOptions = { exportOptions: { 'columns': ':all'} };

            $.extend(true, excelButtonConfig, addOptions);
            excelButtonConfig.action(e, dt, button, excelButtonConfig);
        }).draw();
    }
}

Cela envoie les données de la table entière à l'écran au lieu d'utiliser la pagination et d'envoyer l'ensemble des données dans un fichier Excel.

J'ai effectué des recherches sur Google et ici dans SO, mais je n'ai pas trouvé de solution qui fonctionne.

Je devrais également mentionner que je souhaite tout exporter en fonction des filtres actuellement définis dans le tableau. Pour que l'utilisateur final obtienne une exportation uniquement des lignes qu'il recherche. Ils le limitent généralement à 30k - 40k lignes, toujours avec les colonnes 65+. Je ne permet pas (encore) de supprimer/masquer des colonnes.

EDIT/UPDATE

Voici une considération secondaire: si je ne peux pas tout exporter à partir d'une réponse du serveur, puis-je créer le fichier Excel sur le serveur? Excel n'est pas installé sur mes serveurs et je souhaite tout de même que mon utilisateur final récupère le fichier. Je suis sûr que je devrais trouver un moyen de mettre Excel sur mes serveurs, mais comment puis-je transférer les fichiers créés à l'utilisateur final? Cela serait-il même plus rapide que d'envoyer une réponse avec l'ensemble de données complet et de créer le fichier Excel sur l'ordinateur de l'utilisateur?

MODIFIER

Il m'a été recommandé d'essayer la fonction $.ajax() de jquery pour que cela fonctionne. Si quelqu'un pouvait me donner une idée de la procédure à suivre, j'essaierais cela pour un troisième bouton.

Je peux déjà extraire toutes les données, avec les mêmes filtres et le même tri que ceux ajoutés par l'utilisateur, et le faire avec un bouton. La deuxième tentative ci-dessus le fait mais l'envoie à l'écran. J'ai PHPExcel et un fichier pouvant créer une feuille Excel. Comment pourrais-je prendre ce que je reçois dans ce deuxième bouton et l'envoyer à l'autre fichier pour créer la feuille Excel? Je pensais que l'utilisation de la fonction $.ajax() de jquery pourrait fonctionner, je ne sais tout simplement pas comment l'obtenir. Je sais que je devrai utiliser $_POST car les données pourraient être trop volumineuses pour pouvoir utiliser $_GET afin de les envoyer dans le fichier PHPExcel.

Je peux déjà exporter vers un fichier CSV, mais je dois exporter avec un formatage différent de celui utilisé pour le format CSV. C'est pourquoi je vais utiliser PHPExcel.

EDIT III

J'essaie ceci, bien que cela ne fonctionne pas encore:

{
    text: 'Export all to Excel II',
    action: function (e, dt, button, config)
    {
        dt.one('preXhr', function (e, s, data)
        {
            data.length = -1;
        }).one('export', function (e, settings, json, xhr)
        {
            var excelButtonConfig = $.fn.DataTable.ext.buttons.excelHtml5;
            var addOptions = { exportOptions: { 'columns': ':all'} };

            $.extend(true, excelButtonConfig, addOptions);
            excelButtonConfig.action(e, dt, button, excelButtonConfig);
        })
    }
}

EDIT 4

Espérons que la dernière édition.

Je sais que je dois faire trois choses pour que cela fonctionne:

  1. Obtenir le tri et le filtrage en cours
  2. Obtenir un jeu de données avec une longueur définie à -1
  3. Envoyez-le dans le fichier PHPExcel pour le traitement et la création du fichier Excel Je peux créer un bouton comme celui-ci:

    { texte: 'Exporter toutes les données vers Excel', action:}

Je ne sais tout simplement pas ce que l'action doit être. 

Ma deuxième tentative ci-dessus extrait l'ensemble des données dont j'ai besoin, mais l'envoie à l'écran plutôt qu'à mon fichier PHPExcel (ExportAllToExcel.php). 

J'ai essayé de comprendre cela et je ne suis pas allé très loin. On m'a dit que je devais utiliser $.ajax() pour faire cela, on m'a dit que je n'avais pas besoin de l'utiliser. J'ai essayé avec et sans et je n'ai pas été capable d'aller nulle part.

J'ai aussi essayé d'utiliser ceci sans effet:

$.fn.dataTable.ext.buttons.export =
{
    className: 'buttons-alert',
    "text": "Export All Test",
    action: function (e, dt, node, config)
    {
        var SearchData = dt.search();
        var OrderData = dt.order();
        alert("Test Data for Searching: " + SearchData);
        alert("Test Data for Ordering: " + OrderData);
    }
};
5
Mike

J'ai ce travail, la plupart du temps. Le délai est maintenant écoulé, mais il s’agit d’un problème distinct en raison de la taille insuffisante des données. Pour les petits ensembles de données, cela fonctionne parfaitement.

Voici comment je crée le bouton (c'est le bouton export que j'utilise ici):

"buttons": [{
                extend: 'collection',
                text: 'Selection',
                buttons: ['selectAll', 'selectNone']
            }, {
                extend: 'collection',
                text: 'Export',
                buttons: ['export', 'Excel', 'csv', 'pdf', { extend: 'Excel',
                    text: 'Export Current Page',
                    exportOptions: {
                        modifier: {
                            page: 'current'
                        }
                    },
                    customize: function (xlsx)
                    {
                        var sheet = xlsx.xl.worksheets['sheet1.xml'];
                        $('row:first c', sheet).attr('s', '7');
                    }
                }]
            }
            ]

Ceci est l'initialisation du bouton créé ci-dessus:

$.fn.dataTable.ext.buttons.export =
{
    className: 'buttons-alert',
    id: 'ExportButton',
    text: "Export All Test III",
    action: function (e, dt, node, config)
    {
        var SearchData = dt.rows({ filter: 'applied' }).data();
        var SearchData1 = dt.search();
        console.log(SearchData);
        var OrderData = dt.order();
        console.log(SearchData1);
        var NumCol = SearchData[0].length;
        var NumRow = SearchData.length;
        var SearchData2 = [];
        for (j = 0; j < NumRow; j++)
        {
            var NewSearchData = SearchData[j];
            for (i = 0; i < NewSearchData.length; i++)
            {
                NewSearchData[i] = NewSearchData[i].replace("<div class='Scrollable'>", "");
                NewSearchData[i] = NewSearchData[i].replace("</div>", "");
            }
            SearchData2.Push([NewSearchData]);
        }

        for (i = 0; i < SearchData2.length; i++)
        {
            for (j = 0; j < SearchData2[i].length; j++)
            {
                SearchData2[i][j] = SearchData2[i][j].join('::');
            }
        }
        SearchData2 = SearchData2.join("%%");
        window.location.href = './ServerSide.php?ExportToExcel=Yes';
    }
};

Et voici la partie du fichier ServerSide.php qui récupère les données et les envoie au serveur pour traitement:

require('FilterSort.class.php');

if (isset($_GET['ExportToExcel']) && $_GET['ExportToExcel'] == 'Yes')
{
    $request = @unserialize($_COOKIE['KeepPost']);
    $DataReturn = json_encode(FilterSort::complex($request,$sqlConnect,$table,$primaryKey,$ColumnHeader));
    require './ExportAllToExcel.php';
}
else
{
    echo json_encode(FilterSort::complex($request,$sqlConnect,$table,$primaryKey,$ColumnHeader));
}

Voici comment définir le cookie que j'utilise pour conserver les critères de recherche et de tri:

if(isset($_POST['draw']))
{
    $KeepPost = $_POST;    
    $KeepPost['length'] = -1;
    $PostKept = serialize($KeepPost);
    setcookie("KeepPost",$PostKept,time() + (60*60*24*7));
}

Tous ces éléments combinés envoient les critères corrects à FilterSort.class.php, qui doit les traiter et renvoyer l'ensemble de données à ExportAllToExcell.php, qui crée ensuite le fichier Excel. En ce moment, je lui envoie d’énormes rapports et le délai est écoulé.

METTRE &AGRAVE; JOUR

J'ai légèrement changé ma façon de faire:

Voici le nouvel ensemble de boutons:

"buttons": [{
    extend: 'collection',
    text: 'Export',
    buttons: ['export', { extend: 'csv',
        text: 'Export All To CSV',              //Export all to CSV file
        action: function (e, dt, node, config)
        {
            window.location.href = './ServerSide.php?ExportToCSV=Yes';
        }
    }, 'csv', 'pdf', { extend: 'Excel',
        text: 'Export Current Page',            //Export to Excel only the current page and highlight the first row as headers
        exportOptions: {
            modifier: {
                page: 'current'
            }
        },
        customize: function (xlsx)
        {
            var sheet = xlsx.xl.worksheets['sheet1.xml'];
            $('row:first c', sheet).attr('s', '7');
        }
    }]
}
]

Voici comment je crée le bouton Exporter tout vers Excel:

$.fn.dataTable.ext.buttons.export =
{
    className: 'buttons-alert',                         //Adds the "Export all to Excel" button
    id: 'ExportButton',
    text: "Export All To Excel",
    action: function (e, dt, node, config)
    {
        window.location.href = './ServerSide.php?ExportToExcel=Yes';
    }
};

Ceux-ci envoient maintenant les données au même fichier ServerSide.php que j'utilisais auparavant:

require('FilterSort.class.php');
if (isset($_GET['ExportToExcel']) && $_GET['ExportToExcel'] == 'Yes')
{
    include 'Helper/LogReport.php';
    $GetSQL = "Select Value from PostKept where UserName = '" .$_COOKIE['UserName']. "'";
    $KeepResult = $conn->query($GetSQL);
    $KeepResults = $KeepResult->fetchALL(PDO::FETCH_ASSOC);

    $request = unserialize($KeepResults[0]['Value']);

    $DataReturn = json_encode(FilterSort::complex($request,$sqlConnect,$table,$primaryKey,$ColumnHeader,1));
    require './ExportAllToExcel.php';

J'ai également changé la façon dont je garde la requête, je l'ai maintenant aussi en gardant le Nom de la table et le Nom d'utilisateur comme ceci:

include 'DBConn.php';
$KeepPost = $_POST;                                     //POST holds all the data for the search
$KeepPost['length'] = -1;                               //-1 means pulling the whole table
$PostKept = serialize($KeepPost);                       //This takes the array of data and turns it into a string for storage in SQL
$SQLCheck = "select distinct UserName from PostKept";   //Gets all the distinct Usernames of users that have used the Report Dashboard.
$sth = $conn->query($SQLCheck);
$CheckedUser = $sth->fetchALL(PDO::FETCH_ASSOC);
foreach($CheckedUser as $User)
{
    foreach($User as $Index => $Who)
    {
        $FoundUsers[] = $Who;                           //Taking all the found users and placing them into a simpler array for searching later

    }
}

if(isset($_COOKIE['UserName']) && in_array($_COOKIE['UserName'],$FoundUsers))   //If the user already has an entry update it with new information
{
    $TSQL = "UPDATE PostKept set Value = '" .$PostKept. "', TableName = '" .$TableName. "' where UserName = '" .$_COOKIE['UserName']. "'";
}
else
{
    if(isset($_COOKIE['UserName']))     //If this is a new user
    {
        $TSQL = "INSERT into PostKept(Value, TableName, UserName) select '" .$PostKept. "','" .$TableName. "','" .$_COOKIE['UserName']. "'";
    }
    else        //If this is on the Prod site and the User info is not yet kept
    {
        $TSQL = "INSERT into PostKept(Value, TableName) select '" .$PostKept. "','" .$TableName. "'";
    }
}

$sth = $conn->prepare($TSQL);
$sth->execute();

C’est maintenant ce que tous combinent pour envoyer les données au fichier ExportAllToExcel.php que j’ai et qu’il crée ensuite à son tour.

1
Mike

en boutons:

action: function (e, dt, node, config) {

var formData = 'yourfilters';
formData.begin = '0';
formData.length = 'yourTotalSize';

$http({
    url: 'yourURL',
    method: 'POST',
    data: JSON.stringify(formData)
}).then(function (ajaxReturnedData) {

    dt.rows.add(ajaxReturnedData.data).draw();
    $.fn.dataTable.ext.buttons.excelHtml5.action.call(this, e, dt, node, config);

});}
1
Reza

Je viens juste de le rencontrer et de proposer une solution alternative.

Dans les options DataTable, ajoutez ceci:

"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]

Cela permettra à l'utilisateur de sélectionner toutes les lignes et enverra -1 au serveur dans le paramètre de chaîne de requête 'longueur'. Côté serveur, vous devez gérer le nombre négatif et autoriser le renvoi de toutes les lignes lorsque -1 est reçu.

Cela afficherait toutes les lignes du tableau et les exporterait toutes.

Je comprends que cela peut ne pas convenir pour des lignes de 50 à 60 000 Ko, mais pour un jeu de données plus petit, cela peut fonctionner sans implémentation de code supplémentaire côté serveur et côté client.

0
Prashant Gupta