diff --git a/composer.json b/composer.json
index 9adaf3f7c9..dc4f2b0ffd 100644
--- a/composer.json
+++ b/composer.json
@@ -20,7 +20,8 @@
"gedmo/doctrine-extensions" : "~2.3.0",
"alchemy/google-plus-api-client" : "~0.6.2",
"alchemy/geonames-api-consumer" : "~0.1.0",
- "guzzle/guzzle" : "~3.6",
+ "goodby/csv" : "~1.0",
+ "guzzle/guzzle" : "~3.0",
"igorw/get-in" : "~1.0",
"imagine/imagine" : "0.6.x-dev@dev",
"ircmaxell/random-lib" : "~1.0",
diff --git a/composer.lock b/composer.lock
index ece5645a0c..a3e26ca189 100644
--- a/composer.lock
+++ b/composer.lock
@@ -3,7 +3,7 @@
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
],
- "hash": "88bbe728663cb23ecfba31d240af17c3",
+ "hash": "2b68364c4ebb09b6f5c3902e0afdcc1a",
"packages": [
{
"name": "alchemy-fr/tcpdf-clone",
@@ -1369,6 +1369,64 @@
"tree",
"uploadable"
],
+ "time": "2013-08-18 07:18:44"
+ },
+ {
+ "name": "goodby/csv",
+ "version": "1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/goodby/csv.git",
+ "reference": "da672802985d196cae767da29b11618a676496b0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/goodby/csv/zipball/da672802985d196cae767da29b11618a676496b0",
+ "reference": "da672802985d196cae767da29b11618a676496b0",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "mikey179/vfsstream": ">=1.1.0",
+ "mockery/mockery": ">=0.7.2",
+ "phpunit/phpunit": "3.7.*",
+ "suin/php-expose": ">=1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Goodby\\CSV": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "suin",
+ "email": "suinyeze@gmail.com",
+ "homepage": "https://www.facebook.com/suinyeze",
+ "role": "Developer, Renaming Specialist"
+ },
+ {
+ "name": "reoring",
+ "email": "mori.reo@gmail.com",
+ "homepage": "https://www.facebook.com/reoring",
+ "role": "Developer"
+ }
+ ],
+ "description": "CSV import/export library",
+ "homepage": "https://github.com/goodby/csv",
+ "keywords": [
+ "csv",
+ "export",
+ "import"
+ ],
+ "time": "2013-11-22 19:10:34"
"time": "2014-01-12 16:34:06"
},
{
diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php
index 5c3dfdffe0..543b21a0a2 100644
--- a/lib/Alchemy/Phrasea/Application.php
+++ b/lib/Alchemy/Phrasea/Application.php
@@ -57,7 +57,6 @@ use Alchemy\Phrasea\Controller\Prod\UsrLists;
use Alchemy\Phrasea\Controller\Prod\WorkZone;
use Alchemy\Phrasea\Controller\Report\Activity as ReportActivity;
use Alchemy\Phrasea\Controller\Report\Informations as ReportInformations;
-use Alchemy\Phrasea\Controller\Report\Export as ReportExport;
use Alchemy\Phrasea\Controller\Report\Root as ReportRoot;
use Alchemy\Phrasea\Controller\Root\Account;
use Alchemy\Phrasea\Controller\Root\Developers;
@@ -87,6 +86,7 @@ use Alchemy\Phrasea\Core\Provider\CacheServiceProvider;
use Alchemy\Phrasea\Core\Provider\CacheConnectionServiceProvider;
use Alchemy\Phrasea\Core\Provider\ConfigurationServiceProvider;
use Alchemy\Phrasea\Core\Provider\ConfigurationTesterServiceProvider;
+use Alchemy\Phrasea\Core\Provider\CSVServiceProvider;
use Alchemy\Phrasea\Core\Provider\ConvertersServiceProvider;
use Alchemy\Phrasea\Core\Provider\FileServeServiceProvider;
use Alchemy\Phrasea\Core\Provider\FeedServiceProvider;
@@ -221,6 +221,7 @@ class Application extends SilexApplication
$this->register(new ConfigurationServiceProvider());
$this->register(new ConfigurationTesterServiceProvider);
$this->register(new ConvertersServiceProvider());
+ $this->register(new CSVServiceProvider());
$this->register(new RegistrationServiceProvider());
$this->register(new CacheServiceProvider());
$this->register(new CacheConnectionServiceProvider());
@@ -880,7 +881,6 @@ class Application extends SilexApplication
$this->mount('/report/', new ReportRoot());
$this->mount('/report/activity', new ReportActivity());
$this->mount('/report/informations', new ReportInformations());
- $this->mount('/report/export', new ReportExport());
$this->mount('/thesaurus', new Thesaurus());
$this->mount('/xmlhttp', new ThesaurusXMLHttp());
diff --git a/lib/Alchemy/Phrasea/Controller/Admin/Users.php b/lib/Alchemy/Phrasea/Controller/Admin/Users.php
index b530963b6c..5e51e9deee 100644
--- a/lib/Alchemy/Phrasea/Controller/Admin/Users.php
+++ b/lib/Alchemy/Phrasea/Controller/Admin/Users.php
@@ -11,6 +11,7 @@
namespace Alchemy\Phrasea\Controller\Admin;
+use Alchemy\Phrasea\Core\Response\CSVFileResponse;
use Alchemy\Phrasea\Helper\User as UserHelper;
use Alchemy\Phrasea\Model\Entities\FtpCredential;
use Alchemy\Phrasea\Model\Entities\User;
@@ -148,8 +149,6 @@ class Users implements ControllerProviderInterface
})->bind('admin_users_search');
$controllers->post('/search/export/', function () use ($app) {
- $request = $app['request'];
-
$users = new UserHelper\Manage($app, $app['request']);
$userTable = [
@@ -194,10 +193,10 @@ class Users implements ControllerProviderInterface
];
}
- $CSVDatas = \format::arr_to_csv($userTable);
-
- $response = new Response($CSVDatas, 200, ['Content-Type' => 'text/csv']);
- $response->headers->set('Content-Disposition', 'attachment; filename=export.csv');
+ $filename = sprintf('user_export_%s.csv', date('Ymd'));
+ $response = new CSVFileResponse($filename, function() use ($app, $userTable) {
+ $app['csv.exporter']->export('php://output', $userTable);
+ });
return $response;
})->bind('admin_users_search_export');
@@ -224,7 +223,7 @@ class Users implements ControllerProviderInterface
$have_not_right = $request->query->get('have_not_right') ? : [];
$on_base = $request->query->get('on_base') ? : [];
- $elligible_users = $user_query
+ $eligible_users = $user_query
->on_sbas_where_i_am($app['acl']->get($app['authentication']->getUser()), $rights)
->like(\User_Query::LIKE_EMAIL, $like_value)
->like(\User_Query::LIKE_FIRSTNAME, $like_value)
@@ -239,7 +238,7 @@ class Users implements ControllerProviderInterface
$datas = [];
- foreach ($elligible_users as $user) {
+ foreach ($eligible_users as $user) {
$datas[] = [
'email' => $user->getEmail() ? : '',
'login' => $user->getLogin() ? : '',
@@ -287,7 +286,7 @@ class Users implements ControllerProviderInterface
$on_base = $request->request->get('base_id') ? : null;
$on_sbas = $request->request->get('sbas_id') ? : null;
- $elligible_users = $user_query->on_bases_where_i_am($app['acl']->get($app['authentication']->getUser()), ['canadmin'])
+ $eligible_users = $user_query->on_bases_where_i_am($app['acl']->get($app['authentication']->getUser()), ['canadmin'])
->like($like_field, $like_value)
->on_base_ids($on_base)
->on_sbas_ids($on_sbas);
@@ -314,10 +313,10 @@ class Users implements ControllerProviderInterface
$app->trans('admin::compte-utilisateur activite'),
];
do {
- $elligible_users->limit($offset, 20);
+ $eligible_users->limit($offset, 20);
$offset += 20;
- $results = $elligible_users->execute()->get_results();
+ $results = $eligible_users->execute()->get_results();
foreach ($results as $user) {
$buffer[] = [
@@ -341,14 +340,10 @@ class Users implements ControllerProviderInterface
}
} while (count($results) > 0);
- $out = \format::arr_to_csv($buffer);
-
- $response = new Response($out, 200, [
- 'Content-type' => 'text/csv',
- 'Content-Disposition' => 'attachment; filename=export.csv',
- ]);
-
- $response->setCharset('UTF-8');
+ $filename = sprintf('user_export_%s.csv', date('Ymd'));
+ $response = new CSVFileResponse($filename, function() use ($app, $buffer) {
+ $app['csv.exporter']->export('php://output', $buffer);
+ });
return $response;
})->bind('admin_users_export_csv');
@@ -521,6 +516,7 @@ class Users implements ControllerProviderInterface
})->bind('users_display_import_file');
$controllers->post('/import/file/', function (Application $app, Request $request) {
+
if ((null === $file = $request->files->get('files')) || !$file->isValid()) {
return $app->redirectPath('users_display_import_file', ['error' => 'file-invalid']);
}
@@ -534,7 +530,11 @@ class Users implements ControllerProviderInterface
];
$nbUsrToAdd = 0;
- $lines = \format::csv_to_arr($file->getPathname());
+ $lines = array();
+ $app['csv.interpreter']->addObserver(function(array $row) use (&$lines) {
+ $lines[] = $row;
+ });
+ $app['csv.lexer']->parse($file->getPathname(), $app['csv.interpreter']);
$roughColumns = array_shift($lines);
diff --git a/lib/Alchemy/Phrasea/Controller/Report/Activity.php b/lib/Alchemy/Phrasea/Controller/Report/Activity.php
index 696b0c8214..daa452bc82 100644
--- a/lib/Alchemy/Phrasea/Controller/Report/Activity.php
+++ b/lib/Alchemy/Phrasea/Controller/Report/Activity.php
@@ -11,6 +11,8 @@
namespace Alchemy\Phrasea\Controller\Report;
+use Alchemy\Phrasea\Core\Response\CSVFileResponse;
+use Goodby\CSV\Export\Standard\Collection\CallbackCollection;
use Silex\Application;
use Silex\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Request;
@@ -100,29 +102,23 @@ class Activity implements ControllerProviderInterface
$activity->setHasLimit(false);
$activity->getConnexionBase(false, $request->request->get('on', 'user'));
- try {
- $csv = \format::arr_to_csv($activity->getResult(), $activity->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
-
- return $app->json(['rs' => $csv]);
- } else {
- $report = $activity->getConnexionBase(false, $request->request->get('on', 'user'));
-
- return $app->json([
- 'rs' => $app['twig']->render('report/ajax_data_content.html.twig', [
- 'result' => isset($report['report']) ? $report['report'] : $report,
- 'is_infouser' => false,
- 'is_nav' => false,
- 'is_groupby' => false,
- 'is_plot' => false,
- 'is_doc' => false
- ]),
- 'display_nav' => false,
- 'title' => false
- ]);
+ return $this->getCSVResponse($app, $activity, 'activity_connection_base');
}
+
+ $report = $activity->getConnexionBase(false, $request->request->get('on', 'user'));
+
+ return $app->json([
+ 'rs' => $app['twig']->render('report/ajax_data_content.html.twig', [
+ 'result' => isset($report['report']) ? $report['report'] : $report,
+ 'is_infouser' => false,
+ 'is_nav' => false,
+ 'is_groupby' => false,
+ 'is_plot' => false,
+ 'is_doc' => false
+ ]),
+ 'display_nav' => false,
+ 'title' => false
+ ]);
}
/**
@@ -166,27 +162,21 @@ class Activity implements ControllerProviderInterface
if ($request->request->get('printcsv') == 'on') {
$activity->setHasLimit(false);
- try {
- $csv = \format::arr_to_csv($activity->getResult(), $activity->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
-
- return $app->json(['rs' => $csv]);
- } else {
- return $app->json([
- 'rs' => $app['twig']->render('report/ajax_data_content.html.twig', [
- 'result' => isset($report['report']) ? $report['report'] : $report,
- 'is_infouser' => false,
- 'is_nav' => false,
- 'is_groupby' => false,
- 'is_plot' => false,
- 'is_doc' => false
- ]),
- 'display_nav' => false,
- 'title' => false
- ]);
+ return $this->getCSVResponse($app, $activity, 'activity_detail_download');
}
+
+ return $app->json([
+ 'rs' => $app['twig']->render('report/ajax_data_content.html.twig', [
+ 'result' => isset($report['report']) ? $report['report'] : $report,
+ 'is_infouser' => false,
+ 'is_nav' => false,
+ 'is_groupby' => false,
+ 'is_plot' => false,
+ 'is_doc' => false
+ ]),
+ 'display_nav' => false,
+ 'title' => false
+ ]);
}
/**
@@ -222,29 +212,23 @@ class Activity implements ControllerProviderInterface
$activity->getTopQuestion($conf);
- try {
- $csv = \format::arr_to_csv($activity->getResult(), $activity->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
-
- return $app->json(['rs' => $csv]);
- } else {
- $report = $activity->getTopQuestion($conf);
-
- return $app->json([
- 'rs' => $app['twig']->render('report/ajax_data_content.html.twig', [
- 'result' => isset($report['report']) ? $report['report'] : $report,
- 'is_infouser' => false,
- 'is_nav' => false,
- 'is_groupby' => false,
- 'is_plot' => false,
- 'is_doc' => false
- ]),
- 'display_nav' => false,
- 'title' => false
- ]);
+ return $this->getCSVResponse($app, $activity, 'activity_questions_best_of');
}
+
+ $report = $activity->getTopQuestion($conf);
+
+ return $app->json(array(
+ 'rs' => $app['twig']->render('report/ajax_data_content.html.twig', array(
+ 'result' => isset($report['report']) ? $report['report'] : $report,
+ 'is_infouser' => false,
+ 'is_nav' => false,
+ 'is_groupby' => false,
+ 'is_plot' => false,
+ 'is_doc' => false
+ )),
+ 'display_nav' => false,
+ 'title' => false
+ ));
}
/**
@@ -287,29 +271,23 @@ class Activity implements ControllerProviderInterface
$activity->getTopQuestion($conf, true);
- try {
- $csv = \format::arr_to_csv($activity->getResult(), $activity->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
-
- return $app->json(['rs' => $csv]);
- } else {
- $report = $activity->getTopQuestion($conf, true);
-
- return $app->json([
- 'rs' => $app['twig']->render('report/ajax_data_content.html.twig', [
- 'result' => isset($report['report']) ? $report['report'] : $report,
- 'is_infouser' => false,
- 'is_nav' => false,
- 'is_groupby' => false,
- 'is_plot' => false,
- 'is_doc' => false
- ]),
- 'display_nav' => false,
- 'title' => false
- ]);
+ return $this->getCSVResponse($app, $activity, 'activity_top_ten_questions');
}
+
+ $report = $activity->getTopQuestion($conf, true);
+
+ return $app->json(array(
+ 'rs' => $app['twig']->render('report/ajax_data_content.html.twig', array(
+ 'result' => isset($report['report']) ? $report['report'] : $report,
+ 'is_infouser' => false,
+ 'is_nav' => false,
+ 'is_groupby' => false,
+ 'is_plot' => false,
+ 'is_doc' => false
+ )),
+ 'display_nav' => false,
+ 'title' => false
+ ));
}
/**
@@ -331,33 +309,31 @@ class Activity implements ControllerProviderInterface
$activity->setConfig(false);
- $report = $activity->getActivityPerHours();
+
if ($request->request->get('printcsv') == 'on') {
- $activity->setHasLimit(false);
- $activity->setPrettyString(false);
+ $activity->setHasLimit(false);
+ $activity->setPrettyString(false);
- try {
- $csv = \format::arr_to_csv($activity->getResult(), $activity->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
+ $activity->getActivityPerHours();
- return $app->json(['rs' => $csv]);
- } else {
- return $app->json([
- 'rs' => $app['twig']->render('report/ajax_data_content.html.twig', [
- 'result' => isset($report['report']) ? $report['report'] : $report,
- 'is_infouser' => false,
- 'is_nav' => false,
- 'is_groupby' => false,
- 'is_plot' => true,
- 'is_doc' => false
- ]),
- 'display_nav' => false,
- 'title' => false
- ]);
+ return $this->getCSVResponse($app, $activity, 'activity_per_hours');
}
+
+ $report = $activity->getActivityPerHours();
+
+ return $app->json(array(
+ 'rs' => $app['twig']->render('report/ajax_data_content.html.twig', array(
+ 'result' => isset($report['report']) ? $report['report'] : $report,
+ 'is_infouser' => false,
+ 'is_nav' => false,
+ 'is_groupby' => false,
+ 'is_plot' => true,
+ 'is_doc' => false
+ )),
+ 'display_nav' => false,
+ 'title' => false
+ ));
}
/**
@@ -395,33 +371,29 @@ class Activity implements ControllerProviderInterface
$activity->setConfig(false);
- $report = $activity->getDownloadByBaseByDay($conf);
-
if ($request->request->get('printcsv') == 'on') {
- $activity->setHasLimit(false);
- $activity->setPrettyString(false);
+ $activity->setHasLimit(false);
+ $activity->setPrettyString(false);
- try {
- $csv = \format::arr_to_csv($activity->getResult(), $activity->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
+ $activity->getDownloadByBaseByDay($conf);
- return $app->json(['rs' => $csv]);
- } else {
- return $app->json([
- 'rs' => $app['twig']->render('report/ajax_data_content.html.twig', [
- 'result' => isset($report['report']) ? $report['report'] : $report,
- 'is_infouser' => false,
- 'is_nav' => false,
- 'is_groupby' => false,
- 'is_plot' => false,
- 'is_doc' => false
- ]),
- 'display_nav' => false,
- 'title' => false
- ]);
+ return $this->getCSVResponse($app, $activity, 'activity_db_by_base_by_day');
}
+
+ $report = $activity->getDownloadByBaseByDay($conf);
+
+ return $app->json(array(
+ 'rs' => $app['twig']->render('report/ajax_data_content.html.twig', array(
+ 'result' => isset($report['report']) ? $report['report'] : $report,
+ 'is_infouser' => false,
+ 'is_nav' => false,
+ 'is_groupby' => false,
+ 'is_plot' => false,
+ 'is_doc' => false
+ )),
+ 'display_nav' => false,
+ 'title' => false
+ ));
}
/**
@@ -456,13 +428,9 @@ class Activity implements ControllerProviderInterface
$activity->setHasLimit(false);
$activity->setPrettyString(false);
- try {
- $csv = \format::arr_to_csv($activity->getResult(), $activity->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
+ $this->doReport($app, $request, $activity, $conf);
- return $app->json(['rs' => $csv]);
+ return $this->getCSVResponse($app, $activity, 'activity_pushed_documents');
}
$report = $this->doReport($app, $request, $activity, $conf);
@@ -521,13 +489,9 @@ class Activity implements ControllerProviderInterface
$activity->setHasLimit(false);
$activity->setPrettyString(false);
- try {
- $csv = \format::arr_to_csv($activity->getResult(), $activity->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
+ $this->doReport($app, $request, $activity, $conf);
- return $app->json(['rs' => $csv]);
+ return $this->getCSVResponse($app, $activity, 'activity_added_documents');
}
$report = $this->doReport($app, $request, $activity, $conf);
@@ -586,13 +550,9 @@ class Activity implements ControllerProviderInterface
$activity->setHasLimit(false);
$activity->setPrettyString(false);
- try {
- $csv = \format::arr_to_csv($activity->getResult(), $activity->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
+ $this->doReport($app, $request, $activity, $conf);
- return $app->json(['rs' => $csv]);
+ return $this->getCSVResponse($app, $activity, 'activity_edited_documents');
}
$report = $this->doReport($app, $request, $activity, $conf);
@@ -652,13 +612,9 @@ class Activity implements ControllerProviderInterface
$activity->setHasLimit(false);
$activity->setPrettyString(false);
- try {
- $csv = \format::arr_to_csv($activity->getResult(), $activity->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
+ $this->doReport($app, $request, $activity, $conf);
- return $app->json(['rs' => $csv]);
+ return $this->getCSVResponse($app, $activity, 'activity_validated_documents');
}
$report = $this->doReport($app, $request, $activity, $conf);
@@ -718,13 +674,9 @@ class Activity implements ControllerProviderInterface
$activity->setHasLimit(false);
$activity->setPrettyString(false);
- try {
- $csv = \format::arr_to_csv($activity->getResult(), $activity->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
+ $this->doReport($app, $request, $activity, $conf);
- return $app->json(['rs' => $csv]);
+ return $this->getCSVResponse($app, $activity, 'activity_send_documents');
}
$report = $this->doReport($app, $request, $activity, $conf);
@@ -887,4 +839,39 @@ class Activity implements ControllerProviderInterface
return $reportArray;
}
+
+ /**
+ * Prefix the method to call with the controller class name
+ *
+ * @param string $method The method to call
+ * @return string
+ */
+ private function call($method)
+ {
+ return sprintf('%s::%s', __CLASS__, $method);
+ }
+
+ private function getCSVResponse(Application $app, \module_report $report, $type)
+ {
+ // set headers
+ $headers = array();
+ foreach (array_keys($report->getDisplay()) as $k) {
+ $headers[$k] = $k;
+ }
+ // set headers as first row
+ $result = $report->getResult();
+ array_unshift($result, $headers);
+
+ $collection = new CallbackCollection($result, function($row) use ($report) {
+ // restrict to displayed fields
+ return array_map('strip_tags', array_intersect_key($row, $report->getDisplay()));
+ });
+
+ $filename = sprintf('report_export_%s_%s.csv', $type, date('Ymd'));
+ $response = new CSVFileResponse($filename, function() use ($app, $collection) {
+ $app['csv.exporter']->export('php://output', $collection);
+ });
+
+ return $response;
+ }
}
diff --git a/lib/Alchemy/Phrasea/Controller/Report/Export.php b/lib/Alchemy/Phrasea/Controller/Report/Export.php
deleted file mode 100644
index a8bcbd0c04..0000000000
--- a/lib/Alchemy/Phrasea/Controller/Report/Export.php
+++ /dev/null
@@ -1,74 +0,0 @@
-addMandatoryAuthentication($controllers);
-
- $controllers->before(function () use ($app) {
- $app['firewall']->requireAccessToModule('report');
- });
-
- $controllers->post('/csv', 'controller.report.export:exportCSV')
- ->bind('report_export_csv');
-
- return $controllers;
- }
-
- /**
- * Export data to a csv file
- *
- * @param Application $app
- * @param Request $request
- * @return Response
- */
- public function exportCSV(Application $app, Request $request)
- {
- $name = $request->request->get('name', 'export');
-
- if (null === $data = $request->request->get('csv')) {
- $app->abort(400);
- }
-
- $filename = mb_strtolower('report_' . $name . '_' . date('dmY') . '.csv');
- $data = preg_replace('/[ \t\r\f]+/', '', $data);
-
- $response = new Response($data, 200, [
- 'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
- 'Last-Modified' => gmdate('D, d M Y H:i:s'). ' GMT',
- 'Cache-Control' => 'no-store, no-cache, must-revalidate',
- 'Cache-Control' => 'post-check=0, pre-check=0',
- 'Pragma' => 'no-cache',
- 'Content-Type' => 'text/csv',
- 'Content-Length' => strlen($data),
- 'Cache-Control' => 'max-age=3600, must-revalidate',
- 'Content-Disposition' => 'max-age=3600, must-revalidate',
- ]);
-
- $response->headers->set('Content-Disposition', $response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename));
-
- return $response;
- }
-}
diff --git a/lib/Alchemy/Phrasea/Controller/Report/Informations.php b/lib/Alchemy/Phrasea/Controller/Report/Informations.php
index cdba69d281..b593cc8fe9 100644
--- a/lib/Alchemy/Phrasea/Controller/Report/Informations.php
+++ b/lib/Alchemy/Phrasea/Controller/Report/Informations.php
@@ -11,6 +11,8 @@
namespace Alchemy\Phrasea\Controller\Report;
+use Alchemy\Phrasea\Core\Response\CSVFileResponse;
+use Goodby\CSV\Export\Standard\Collection\CallbackCollection;
use Silex\Application;
use Silex\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Request;
@@ -183,13 +185,7 @@ class Informations implements ControllerProviderInterface
if ($request->request->get('printcsv') == 'on') {
$report->setPrettyString(false);
- try {
- $csv = \format::arr_to_csv($report->getResult(), $report->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
-
- return $app->json(['rs' => $csv]);
+ return $this->getCSVResponse($app, $report, 'info_user');
}
$html = $app['twig']->render('report/ajax_data_content.html.twig', [
@@ -432,13 +428,7 @@ class Informations implements ControllerProviderInterface
if ($request->request->get('printcsv') == 'on') {
$download->setPrettyString(false);
- try {
- $csv = \format::arr_to_csv($download->getResult(), $download->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
-
- return $app->json(['rs' => $csv]);
+ return $this->getCSVResponse($app, $download, 'info_document');
}
$html .= $app['twig']->render('report/ajax_data_content.html.twig', [
@@ -481,15 +471,8 @@ class Informations implements ControllerProviderInterface
$reportArray = $info->buildTabGrpInfo(false, [], $request->request->get('user'), $conf, false);
if ($request->request->get('printcsv') == 'on' && isset($download)) {
- $download->setPrettyString(false);
- try {
- $csv = \format::arr_to_csv($download->getResult(), $download->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
-
- return $app->json(['rs' => $csv]);
+ return $this->getCSVResponse($app, $info, 'info_user');
}
$html .= $app['twig']->render('report/ajax_data_content.html.twig', [
@@ -512,6 +495,41 @@ class Informations implements ControllerProviderInterface
'rs' => $html,
'display_nav' => false,
'title' => $title
- ]);
+ ));
+ }
+
+ /**
+ * Prefix the method to call with the controller class name
+ *
+ * @param string $method The method to call
+ * @return string
+ */
+ private function call($method)
+ {
+ return sprintf('%s::%s', __CLASS__, $method);
+ }
+
+ private function getCSVResponse(Application $app, \module_report $report, $type)
+ {
+ // set headers
+ $headers = array();
+ foreach (array_keys($report->getDisplay()) as $k) {
+ $headers[$k] = $k;
+ }
+ // set headers as first row
+ $result = $report->getResult();
+ array_unshift($result, $headers);
+
+ $collection = new CallbackCollection($result, function($row) use ($report) {
+ // restrict fields to the displayed ones
+ return array_map('strip_tags', array_intersect_key($row, $report->getDisplay()));
+ });
+
+ $filename = sprintf('report_export_%s_%s.csv', $type, date('Ymd'));
+ $response = new CSVFileResponse($filename, function() use ($app, $collection) {
+ $app['csv.exporter']->export('php://output', $collection);
+ });
+
+ return $response;
}
}
diff --git a/lib/Alchemy/Phrasea/Controller/Report/Root.php b/lib/Alchemy/Phrasea/Controller/Report/Root.php
index db3b440fc1..5b0b84e954 100644
--- a/lib/Alchemy/Phrasea/Controller/Report/Root.php
+++ b/lib/Alchemy/Phrasea/Controller/Report/Root.php
@@ -11,11 +11,14 @@
namespace Alchemy\Phrasea\Controller\Report;
+use Alchemy\Phrasea\Core\Response\CSVFileResponse;
+use Goodby\CSV\Export\Standard\Collection\CallbackCollection;
use Silex\Application;
use Silex\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\HttpFoundation\ResponseHeaderBag;
class Root implements ControllerProviderInterface
{
@@ -202,13 +205,7 @@ class Root implements ControllerProviderInterface
$this->doReport($app, $request, $cnx, $conf);
- try {
- $csv = \format::arr_to_csv($cnx->getResult(), $cnx->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
-
- return $app->json(['rs' => $csv]);
+ return $this->getCSVResponse($app, $cnx, 'connections');
}
$report = $this->doReport($app, $request, $cnx, $conf);
@@ -269,13 +266,7 @@ class Root implements ControllerProviderInterface
$this->doReport($app, $request, $questions, $conf);
- try {
- $csv = \format::arr_to_csv($questions->getResult(), $questions->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
-
- return $app->json(['rs' => $csv]);
+ return $this->getCSVResponse($app, $questions, 'questions');
}
$report = $this->doReport($app, $request, $questions, $conf);
@@ -345,13 +336,7 @@ class Root implements ControllerProviderInterface
$this->doReport($app, $request, $download, $conf);
- try {
- $csv = \format::arr_to_csv($download->getResult(), $download->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
-
- return $app->json(['rs' => $csv]);
+ return $this->getCSVResponse($app, $download, 'download');
}
$report = $this->doReport($app, $request, $download, $conf);
@@ -417,13 +402,7 @@ class Root implements ControllerProviderInterface
$this->doReport($app, $request, $document, $conf, 'record_id');
- try {
- $csv = \format::arr_to_csv($document->getResult(), $document->getDisplay());
- } catch (\Exception $e) {
- $csv = '';
- }
-
- return $app->json(['rs' => $csv]);
+ return $this->getCSVResponse($app, $document, 'documents');
}
$report = $this->doReport($app, $request, $document, $conf, 'record_id');
@@ -503,17 +482,39 @@ class Root implements ControllerProviderInterface
'combo' => $nav->buildTabCombo($conf_combo)
];
- if ($request->request->get('printcsv') == 'on') {
- return $app->json([
- 'nav' => \format::arr_to_csv($report['nav']['result'], $conf_nav),
- 'os' => \format::arr_to_csv($report['os']['result'], $conf_os),
- 'res' => \format::arr_to_csv($report['res']['result'], $conf_res),
- 'mod' => \format::arr_to_csv($report['mod']['result'], $conf_mod),
- 'combo' => \format::arr_to_csv($report['combo']['result'], $conf_combo)
- ]);
- }
+ if ($request->request->get('printcsv') == 'on') {
+ $result = array();
- return $app->json([
+ $result[] = array_keys($conf_nav);
+ foreach($report['nav']['result'] as $row) {
+ $result[] = array_values($row);
+ };
+ $result[] = array_keys($conf_os);
+ foreach($report['os']['result'] as $row) {
+ $result[] = array_values($row);
+ };
+ $result[] = array_keys($conf_res);
+ foreach($report['res']['result'] as $row) {
+ $result[] = array_values($row);
+ };
+ $result[] = array_keys($conf_mod);
+ foreach($report['mod']['result'] as $row) {
+ $result[] = array_values($row);
+ };
+ $result[] = array_keys($conf_combo);
+ foreach($report['combo']['result'] as $row) {
+ $result[] = array_values($row);
+ };
+
+ $filename = sprintf('report_export_info_%s.csv', date('Ymd'));
+ $response = new CSVFileResponse($filename, function() use ($app, $result) {
+ $app['csv.exporter']->export('php://output', $result);
+ });
+
+ return $response;
+ }
+
+ return $app->json([
'rs' => $app['twig']->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
@@ -662,4 +663,39 @@ class Root implements ControllerProviderInterface
return $reportArray;
}
+
+ /**
+ * Prefix the method to call with the controller class name
+ *
+ * @param string $method The method to call
+ * @return string
+ */
+ private function call($method)
+ {
+ return sprintf('%s::%s', __CLASS__, $method);
+ }
+
+ private function getCSVResponse(Application $app, \module_report $report, $type)
+ {
+ // set headers
+ $headers = array();
+ foreach (array_keys($report->getDisplay()) as $k) {
+ $headers[$k] = $k;
+ }
+ // set headers as first row
+ $result = $report->getResult();
+ array_unshift($result, $headers);
+
+ $collection = new CallbackCollection($result, function($row) use ($report) {
+ // restrict fields to the displayed ones
+ return array_map('strip_tags', array_intersect_key($row, $report->getDisplay()));
+ });
+
+ $filename = sprintf('report_export_%s_%s.csv', $type, date('Ymd'));
+ $response = new CSVFileResponse($filename, function() use ($app, $collection) {
+ $app['csv.exporter']->export('php://output', $collection);
+ });
+
+ return $response;
+ }
}
diff --git a/lib/Alchemy/Phrasea/Core/Provider/CSVServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/CSVServiceProvider.php
new file mode 100644
index 0000000000..be841339f3
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Core/Provider/CSVServiceProvider.php
@@ -0,0 +1,77 @@
+share(function () {
+ $config = new ExporterConfig();
+ return $config
+ ->setDelimiter(",")
+ ->setEnclosure('"')
+ ->setEscape("\\")
+ ->setToCharset('UTF-8')
+ ->setFromCharset('UTF-8');
+
+ });
+
+ $app['csv.exporter'] = $app->share(function ($app) {
+ return new Exporter($app['csv.exporter.config']);
+ });
+
+ $app['csv.lexer.config'] = $app->share(function ($app) {
+ return new LexerConfig();
+ });
+
+ $app['csv.lexer'] = $app->share(function ($app) {
+ return new Lexer($app['csv.lexer.config']);
+ });
+
+ $app['csv.interpreter'] = $app->share(function ($app) {
+ return new Interpreter();
+ });
+
+ $app['csv.response'] = $app->protect(function ($callback) use ($app) {
+ // set headers to fix ie issues
+ $response = new StreamedResponse($callback, 200, array(
+ 'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
+ 'Last-Modified' => gmdate('D, d M Y H:i:s'). ' GMT',
+ 'Cache-Control' => 'no-store, no-cache, must-revalidate',
+ 'Cache-Control' => 'post-check=0, pre-check=0',
+ 'Pragma' => 'no-cache',
+ 'Content-Type' => 'text/csv',
+ 'Cache-Control' => 'max-age=3600, must-revalidate',
+ 'Content-Disposition' => 'max-age=3600, must-revalidate',
+ ));
+
+ $response->headers->set('Content-Disposition', $response->headers->makeDisposition(
+ ResponseHeaderBag::DISPOSITION_ATTACHMENT,
+ 'export.csv'
+ ));
+ });
+ }
+
+ public function boot(Application $app)
+ {
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Core/Response/CSVFileResponse.php b/lib/Alchemy/Phrasea/Core/Response/CSVFileResponse.php
new file mode 100644
index 0000000000..19863dfcee
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Core/Response/CSVFileResponse.php
@@ -0,0 +1,43 @@
+ 'Mon, 26 Jul 1997 05:00:00 GMT',
+ 'Last-Modified' => gmdate('D, d M Y H:i:s'). ' GMT',
+ 'Cache-Control' => 'no-store, no-cache, must-revalidate',
+ 'Cache-Control' => 'post-check=0, pre-check=0',
+ 'Pragma' => 'no-cache',
+ 'Cache-Control' => 'max-age=3600, must-revalidate',
+ 'Content-Disposition' => 'max-age=3600, must-revalidate',
+ ),
+ $headers
+ ));
+
+ $this->headers->set('Content-Type', 'text/csv');
+
+ $this->headers->set('Content-Disposition', $this->headers->makeDisposition(
+ ResponseHeaderBag::DISPOSITION_ATTACHMENT,
+ $filename,
+ // ascii filename fallback
+ false === preg_match('/^[\x20-\x7e]*$/', $filename) ? '' : preg_replace('/[^(x20-x7F)]*$/', '', $filename)
+ ));
+ }
+}
\ No newline at end of file
diff --git a/lib/classes/format.php b/lib/classes/format.php
deleted file mode 100644
index eb88f5149b..0000000000
--- a/lib/classes/format.php
+++ /dev/null
@@ -1,97 +0,0 @@
- $value) {
- foreach ($tmp as $k => $v) {
- if ($key == $k) {
- $line[] = '"' . str_replace('"', '""', strip_tags($v)) . '"';
- }
- }
- }
- }
-
- if ($tri_column && count($tri_column) == count($line)) {
- return implode(",", $line);
- } elseif (count($arr) == count($line)) {
- return implode(",", $line);
- } else
- throw new Exception('CSV failed');
- }
-
- public static function arr_to_csv($arr, $tri_column = false)
- {
- $lines = [];
-
- if ($tri_column) {
- $title = "";
- foreach ($tri_column as $v) {
- if (isset($v['title']))
- $title .= ( empty($title) ? "" : ",") . '"' . str_replace('"', '""', strip_tags($v['title'])) . '"';
- }
- ! empty($title) ? $lines[] = $title : "";
- }
- foreach ($arr as $v) {
- $lines[] = self::arr_to_csv_line($v, $tri_column);
- }
-
- return implode("\n", $lines);
- }
-
- public static function csv_to_arr($filename)
- {
- $separateur = ",";
- $array = [];
- // For mac
- $autoDetectLineEndings = ini_get("auto_detect_line_endings");
-
- ini_set("auto_detect_line_endings", true);
-
- if ($file = fopen($filename, "r")) {
- $test1 = fgetcsv($file, 1024, ",");
- rewind($file);
- $test2 = fgetcsv($file, 1024, ";");
- rewind($file);
-
- if (count($test1) == 1 || ( count($test2) > count($test1) && count($test2) < 20)) {
- $separateur = ";";
- }
-
- while ($array[] = fgetcsv($file, 1024, $separateur));
- fclose($file);
- array_pop($array);
- }
-
- ini_set("auto_detect_line_endings", $autoDetectLineEndings);
-
- return $array;
- }
-}
diff --git a/templates/web/report/generate_tab.html.twig b/templates/web/report/generate_tab.html.twig
index 4624f8e5f7..17a9cffbcd 100644
--- a/templates/web/report/generate_tab.html.twig
+++ b/templates/web/report/generate_tab.html.twig
@@ -18,12 +18,9 @@
{% endif %}
{% if result.csv %}
-