Merge branch '3.8'

Conflicts:
	composer.json
	composer.lock
	lib/Alchemy/Phrasea/Application.php
	lib/Alchemy/Phrasea/Controller/Admin/Publications.php
	lib/Alchemy/Phrasea/Controller/Admin/Users.php
	lib/Alchemy/Phrasea/Controller/Client/Root.php
	lib/Alchemy/Phrasea/Controller/Prod/Feed.php
	lib/Alchemy/Phrasea/Controller/Prod/Root.php
	lib/Alchemy/Phrasea/Controller/Report/Activity.php
	lib/Alchemy/Phrasea/Controller/Report/Export.php
	lib/Alchemy/Phrasea/Controller/Report/Informations.php
	lib/Alchemy/Phrasea/Controller/Report/Root.php
	lib/classes/API/V1/adapter.php
	lib/classes/Feed/Aggregate.php
	lib/classes/Feed/Collection.php
	lib/classes/format.php
	tests/Alchemy/Tests/Phrasea/Controller/Admin/PublicationTest.php
	tests/Alchemy/Tests/Phrasea/Controller/Prod/FeedTest.php
	tests/Alchemy/Tests/Phrasea/Controller/Report/ExportTest.php
	tests/Alchemy/Tests/Phrasea/Controller/Root/RSSFeedTest.php
	tests/classes/Feed/Feed_CollectionTest.php
	tests/classes/api/v1/api_v1_adapterTest.php
This commit is contained in:
Nicolas Le Goff
2014-03-30 09:00:17 +02:00
15 changed files with 482 additions and 501 deletions

View File

@@ -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",

60
composer.lock generated
View File

@@ -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"
},
{

View File

@@ -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());

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -1,74 +0,0 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Controller\Report;
use Silex\Application;
use Silex\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
class Export implements ControllerProviderInterface
{
public function connect(Application $app)
{
$app['controller.report.export'] = $this;
$controllers = $app['controllers_factory'];
$app['firewall']->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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,77 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Provider;
use Silex\Application;
use Silex\ServiceProviderInterface;
use Goodby\CSV\Export\Standard\Exporter;
use Goodby\CSV\Export\Standard\ExporterConfig;
use Goodby\CSV\Import\Standard\Lexer;
use Goodby\CSV\Import\Standard\Interpreter;
use Goodby\CSV\Import\Standard\LexerConfig;
use Symfony\Component\HttpFoundation\StreamedResponse;
class CSVServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['csv.exporter.config'] = $app->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)
{
}
}

View File

@@ -0,0 +1,43 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2013 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
class CSVFileResponse extends StreamedResponse
{
public function __construct($filename, $callback = null, $status = 200, $headers = array())
{
parent::__construct($callback, $status, array_merge(
// set some headers to fix ie issues
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',
'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)
));
}
}

View File

@@ -1,97 +0,0 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class format
{
public static function arr_to_csv_line($arr, $tri_column = false)
{
$line = [];
$tmp = [];
foreach ($arr as $v) {
if (is_array($v)) {
$line[] = self::arr_to_csv_line($v);
} elseif ($tri_column) {
$key = array_search($v, $arr);
unset($arr[$key]);
if (array_key_exists($key, $tri_column)) {
$tmp[$key] = $v;
}
} else
$line[] = '"' . str_replace('"', '""', strip_tags($v)) . '"';
}
if ($tri_column) {
foreach ($tri_column as $key => $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;
}
}

View File

@@ -18,12 +18,9 @@
<a href="#" class="jqprint left"><img title="{{ 'report :: imprimer le tableau' | trans }}" src="/skins/report/img/print.png"/></a>
{% endif %}
{% if result.csv %}
<form class="form_csv left" method="POST" action="{{ path('report_export_csv') }}" target="iframe" >
<input type="submit" name ="submit" value=""/>
<input style="display:none;" type="submit" name="doit"/>
<input type="hidden" name="name" value="{{ result.title }}" size="68"/>
<textarea style="display:none;" name="csv"></textarea>
</form>
<a id="export_csv" class="left" href="#" style="display:inline-block; width: 20px;height:20px;margin-left: 10px;">
<img title="{{ 'CSV export' | trans }}" src="/skins/report/img/csv.gif">
</a>
{% endif %}
</div>
<div class="right">{{ result.periode }}</div>

View File

@@ -217,7 +217,8 @@ class UsersTest extends \PhraseanetAuthenticatedWebTestCase
$response = self::$DI['client']->getResponse();
$this->assertTrue($response->isOK());
$this->assertEquals("text/csv; charset=UTF-8", $response->headers->get("Content-type"));
$this->assertEquals("attachment; filename=export.csv", $response->headers->get("content-disposition"));
$date = new \DateTime();
$this->assertEquals('attachment; filename="user_export_'.$date->format('Ymd').'.csv"', $response->headers->get("content-disposition"));
}
public function testRouteThSearch()
@@ -319,7 +320,8 @@ class UsersTest extends \PhraseanetAuthenticatedWebTestCase
$this->assertTrue($response->isOK());
$this->assertRegexp("#text/csv#", $response->headers->get("content-type"));
$this->assertRegexp("#charset=UTF-8#", $response->headers->get("content-type"));
$this->assertEquals("attachment; filename=export.csv", $response->headers->get("content-disposition"));
$date = new \DateTime();
$this->assertEquals('attachment; filename="user_export_'.$date->format('Ymd').'.csv"', $response->headers->get("content-disposition"));
}
public function testResetRights()

View File

@@ -1,26 +0,0 @@
<?php
namespace Alchemy\Tests\Phrasea\Controller\Report;
class ExportTest extends \PhraseanetAuthenticatedWebTestCase
{
public function testExportCSV()
{
$data = 'Year,Make,Model
1997,Ford,E350
2000,Mercury,Cougar';
self::$DI['client']->request('POST', '/report/export/csv', [
'csv' => $data,
'name' => 'test',
]);
$response = self::$DI['client']->getResponse();
$this->assertTrue($response->isOk());
$this->assertRegexp('/attachment/', $response->headers->get('content-disposition'));
$this->assertRegexp('/report_test/', $response->headers->get('content-disposition'));
}
}

View File

@@ -790,68 +790,27 @@ function print() {
}
function csv() {
var button = $(".form_csv input[name=submit]");
var button = $("#export_csv");
button.unbind("click").bind("click", function (e) {
e.preventDefault();
var $this = $(this);
var $formm = $this.closest("form");
if ($this.closest("#dialog").length > 0) {
var $form = $("#dialog").data("dataForm");
}
else {
} else {
var $form = $this.closest(".ui-tabs-panel").find(".report_form");
}
$form.find("input[name=printcsv]").val("on");
//clone form and submit
var clone = $form.clone().appendTo($this);
if (button.data('ajaxRunning')) {
button.data('ajaxQuery').abort();
button.data('ajaxRunning', false);
}
clone.attr("action", $form.find("input[name=action]").val())
.attr("method",'POST')
.removeAttr("onsubmit")
.find("input[name=printcsv]").val("on");
var query = $.ajax({
type: "POST",
url: $form.find("input[name=action]").val(),
dataType: "json",
data: $form.serializeArray(),
beforeSend: function () {
$formm.after("<div></div>");
$formm.next("div").addClass("onload");
button.data('ajaxRunning', true);
},
timeOut: function () {
button.data('ajaxRunning', false);
},
error: function () {
button.data('ajaxRunning', false);
},
success: function (data) {
$formm.next("div").remove();
button.data('ajaxRunning', false);
$form.find("input[name=printcsv]").val("off");
if (typeof data.rs === "object") {
var $key = $this.closest("table").attr("class");
var $csv = data.rs[$key];
$formm.find("textarea[name=csv]").val($csv);
}
else if (data.rs === false) {
$("body").append("<div id='dialog'>Une erreur s'est produite</div>");
$("#dialog").dialog({
close: function () {
$(this).remove();
}
});
}
else {
$formm.find("textarea[name=csv]").val(data.rs);
}
$formm.find("input[name=doit]").trigger('click');
}
});
button.data('ajaxQuery', query);
$(clone).submit().remove();
});
}