3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
10 * Copyright © 2009-2023 The Galette Team
12 * This file is part of Galette (http://galette.tuxfamily.org).
14 * Galette is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
19 * Galette is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2009-2023 The Galette Team
32 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
33 * @link http://galette.tuxfamily.org
34 * @since Disponible depuis la Release 0.7alpha - 2009-02-09
40 use Laminas\Db\ResultSet\ResultSet
;
41 use Symfony\Component\Yaml\Yaml
;
44 use Laminas\Db\Adapter\Adapter
;
52 * @author Johan Cwiklinski <johan@x-tnd.be>
53 * @copyright 2009-2023 The Galette Team
54 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
55 * @link http://galette.tuxfamily.org
56 * @since Disponible depuis la Release 0.7alpha - 2009-02-09
59 class CsvOut
extends Csv
61 public const DEFAULT_DIRECTORY
= GALETTE_EXPORTS_PATH
;
64 private $parameted_path;
65 private $legacy_parameted_file = 'exports.xml';
66 private $parameted_file = 'exports.yaml';
71 public function __construct()
73 parent
::__construct(self
::DEFAULT_DIRECTORY
);
74 $this->parameted_path
= GALETTE_CONFIG_PATH
;
75 $this->parameted_file
= $this->parameted_path
. $this->parameted_file
;
76 $this->legacy_parameted_file
= $this->parameted_path
. $this->legacy_parameted_file
;
80 * Export Array result set to CSV
82 * @param ResultSet $rs Results as an array
83 * @param string $separator The CSV separator (either '\t', ';' or ','
85 * @param string $quote how does fields should be quoted
86 * @param bool $titles does export shows column titles or not.
88 * @param resource|false $file export to a file on disk. A file pointer
89 * should be passed here. Defaults to false.
91 * @return string CSV result
93 public function export($rs, $separator, $quote, $titles = false, $file = false)
95 //switch back to the default separator if not in accepted_separators array
96 if (!in_array($separator, $this->accepted_separators
)) {
97 $separator = self
::DEFAULT_SEPARATOR
;
99 //switch back to the default quote if not in accepted_quotes array
100 if (!in_array($quote, $this->accepted_quotes
)) {
101 $quote = self
::DEFAULT_QUOTE
;
106 if (count($rs) > 0) {
107 foreach ($rs as $row) {
111 $this->separator
= $separator;
112 $this->quote
= $quote;
113 //dubbing quote for escaping
114 $this->escaped
= $quote . $quote;
116 $this->current_line
= 0;
119 if ($titles && !is_array($titles)) {
121 foreach (array_keys((array)$row) as $field) {
122 $fields[] = $this->quote
. str_replace(
128 $this->result
.= implode($this->separator
, $fields) . self
::NEWLINE
;
129 } elseif ($titles && is_array($titles) && count($titles) > 1) {
130 foreach ($titles as $field) {
131 $field = str_replace(
132 array(':', ' '),
136 $fields[] = $this->quote
. str_replace(
142 $this->result
.= implode($this->separator
, $fields) . self
::NEWLINE
;
145 foreach ($results as $row) {
148 if (is_array($row) ||
is_object($row)) {
149 foreach ($row as $v) {
150 $elts[] = $this->quote
. str_replace(
157 $this->result
.= implode($this->separator
, $elts) . self
::NEWLINE
;
159 $this->current_line +
= 1;
165 return $this->result
;
170 * If a file is defined, export will be outputted into it.
171 * If not, it will be returned
173 * @param bool $last true if we write the latest line
177 private function write($last = false)
181 ||
!$last && $this->file
182 && ($this->current_line % self
::BUFLINES
) == 0
184 if ($this->file
=== true) {
187 fwrite($this->file
, $this->result
);
194 * Retrieve parameted export name
196 * @param string $id Parameted export identifier
200 public function getParamedtedExportName($id)
202 //check first in YAML configuration file
203 $data = Yaml
::parseFile($this->parameted_file
);
204 foreach ($data as $export) {
205 if (!isset($export['inactive']) ||
$export['inactive']) {
206 $keys = array_keys($export);
207 $anid = array_shift($keys);
209 return $export['name'];
214 //if id has not been found, look for it in legacy XML configuration file
215 if (file_exists($this->legacy_parameted_file
)) {
216 $xml = simplexml_load_file($this->legacy_parameted_file
);
217 $xpath = $xml->xpath(
218 '/exports/export[@id=\'' . $id . '\'][1]/@name'
220 return (string)$xpath[0];
227 * Get al list of all parameted exports
231 public function getParametedExports()
235 //first, load legacy config; if exists
236 if (file_exists($this->legacy_parameted_file
)) {
237 $xml = simplexml_load_file($this->legacy_parameted_file
);
239 foreach ($xml->export
as $export) {
240 if (!($export['inactive'] == 'inactive')) {
241 $id = (string)$export['id'];
242 $parameted[$id] = array(
244 'name' => (string)$export['name'],
245 'description' => (string)$export['description']
251 //then, load config from YAML file
252 $data = Yaml
::parseFile($this->parameted_file
);
253 foreach ($data as $export) {
254 if (!isset($export['inactive']) ||
$export['inactive']) {
255 $keys = array_keys($export);
256 $id = array_shift($keys);
259 'name' => $export['name'],
260 'description' => $export['description']
269 * Run selected export parameted as XML
271 * @param string $id export's id to run
273 * @return string|int filename used or error code
275 private function runXmlParametedExport($id)
279 $xml = simplexml_load_file($this->legacy_parameted_file
);
281 $xpath = $xml->xpath(
282 '/exports/export[@id=\'' . $id . '\'][not(@inactive)][1]'
287 $results = $zdb->db
->query(
288 str_replace('galette_', PREFIX_DB
, $export->query
),
289 Adapter
::QUERY_MODE_EXECUTE
292 $filename = self
::DEFAULT_DIRECTORY
. $export['filename'];
294 $fp = fopen($filename, 'w');
296 $separator = ($export->separator
)
298 : self
::DEFAULT_SEPARATOR
;
299 $quote = ($export->quote
) ?
$export->quote
: self
::DEFAULT_QUOTE
;
300 if ($export->headers
->none
) {
304 $xpath = $export->xpath('headers/header');
305 if (count($xpath) == 0) {
310 foreach ($xpath as $header) {
311 $title[] = (string)$header;
316 $this->export($results, $separator, $quote, $title, $fp);
320 'File ' . $filename . ' is not writeable.',
323 return self
::FILE_NOT_WRITABLE
;
325 return $export['filename'];
326 } catch (Throwable
$e) {
328 'An error occurred while exporting | ' . $e->getMessage(),
331 return self
::DB_ERROR
;
336 * Run selected export parameted as YAML
338 * @param string $id export's id to run
340 * @return string|int|false filename used, error code or failure
342 private function runYamlParametedExport($id)
347 $data = Yaml
::parseFile($this->parameted_file
);
348 foreach ($data as $anexport) {
349 if (!isset($anexport['inactive']) ||
$anexport['inactive']) {
350 $keys = array_keys($anexport);
351 $anid = array_shift($keys);
358 if ($export['inactive'] ??
false) {
363 $results = $zdb->db
->query(
364 str_replace('galette_', PREFIX_DB
, $export['query']),
365 Adapter
::QUERY_MODE_EXECUTE
368 $filename = self
::DEFAULT_DIRECTORY
. $export['filename'];
370 $fp = fopen($filename, 'w');
372 $separator = $export['separator'] ?? self
::DEFAULT_SEPARATOR
;
373 $quote = $export['quote'] ?? self
::DEFAULT_QUOTE
;
375 if (isset($export['headers'])) {
376 if ($export['headers'] === false) {
380 foreach ($export['headers'] as $header) {
381 $title[] = (string)$header;
386 $this->export($results, $separator, $quote, $title, $fp);
390 'File ' . $filename . ' is not writeable.',
393 return self
::FILE_NOT_WRITABLE
;
395 return $export['filename'];
396 } catch (Throwable
$e) {
398 'An error occurred while exporting | ' . $e->getMessage(),
401 return self
::DB_ERROR
;
406 * Run selected export
408 * @param string $id export's id to run
410 * @return string filename used
412 public function runParametedExport($id)
414 //try first to run from YAML configuration file
415 return $this->runYamlParametedExport($id);
417 //if nothing has been run yet, look into legacy XML configuration file
418 if (file_exists($this->legacy_parameted_file
)) {
419 return $this->runXmlParametedExport($id);