1<?php
2/* Copyright (C) 2006-2008 Laurent Destailleur  <eldy@users.sourceforge.net>
3 * Copyright (C) 2012      Marcos García        <marcosgdf@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17*/
18
19/**
20 *		\file       htdocs/core/modules/export/export_csv.modules.php
21 *		\ingroup    export
22 *		\brief      File of class to build export files with format TSV
23 */
24
25require_once DOL_DOCUMENT_ROOT.'/core/modules/export/modules_export.php';
26
27
28/**
29 *	Class to build export files with format TSV
30 */
31class ExportTsv extends ModeleExports
32{
33	/**
34	 * @var string ID
35	 */
36	public $id;
37
38	/**
39	 * @var string label
40	 */
41	public $label;
42
43	public $extension;
44
45	/**
46	 * Dolibarr version of the loaded document
47	 * @var string
48	 */
49	public $version = 'dolibarr';
50
51	public $label_lib;
52
53	public $version_lib;
54
55	public $separator = "\t";
56
57	public $handle; // Handle fichier
58
59
60	/**
61	 *  Constructor
62	 *
63	 *  @param      DoliDB	$db      Database handler
64	 */
65	public function __construct($db)
66	{
67		global $conf, $langs;
68		$this->db = $db;
69
70		$this->id = 'tsv'; // Same value then xxx in file name export_xxx.modules.php
71		$this->label = 'TSV'; // Label of driver
72		$this->desc = $langs->trans('TsvFormatDesc');
73		$this->extension = 'tsv'; // Extension for generated file by this driver
74		$this->picto = 'mime/other'; // Picto
75		$this->version = '1.15'; // Driver version
76
77		// If driver use an external library, put its name here
78		$this->label_lib = 'Dolibarr';
79		$this->version_lib = DOL_VERSION;
80	}
81
82	/**
83	 * getDriverId
84	 *
85	 * @return string
86	 */
87	public function getDriverId()
88	{
89		return $this->id;
90	}
91
92	/**
93	 * getDriverLabel
94	 *
95	 * @return 	string			Return driver label
96	 */
97	public function getDriverLabel()
98	{
99		return $this->label;
100	}
101
102	/**
103	 * getDriverDesc
104	 *
105	 * @return string
106	 */
107	public function getDriverDesc()
108	{
109		return $this->desc;
110	}
111
112	/**
113	 * getDriverExtension
114	 *
115	 * @return string
116	 */
117	public function getDriverExtension()
118	{
119		return $this->extension;
120	}
121
122	/**
123	 * getDriverVersion
124	 *
125	 * @return string
126	 */
127	public function getDriverVersion()
128	{
129		return $this->version;
130	}
131
132	/**
133	 * getLibLabel
134	 *
135	 * @return string
136	 */
137	public function getLibLabel()
138	{
139		return $this->label_lib;
140	}
141
142	/**
143	 * getLibVersion
144	 *
145	 * @return string
146	 */
147	public function getLibVersion()
148	{
149		return $this->version_lib;
150	}
151
152
153	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
154	/**
155	 *   Open output file
156	 *
157	 *  @param      string		$file			Path of filename to generate
158	 *  @param      Translate	$outputlangs	Output language object
159	 *  @return     int							<0 if KO, >=0 if OK
160	 */
161	public function open_file($file, $outputlangs)
162	{
163		// phpcs:enable
164		global $langs;
165
166		dol_syslog("ExportTsv::open_file file=".$file);
167
168		$ret = 1;
169
170		$outputlangs->load("exports");
171		$this->handle = fopen($file, "wt");
172		if (!$this->handle)
173		{
174			$langs->load("errors");
175			$this->error = $langs->trans("ErrorFailToCreateFile", $file);
176			$ret = -1;
177		}
178
179		return $ret;
180	}
181
182	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
183	/**
184	 * 	Output header into file
185	 *
186	 * 	@param		Translate	$outputlangs		Output language object
187	 * 	@return		int								<0 if KO, >0 if OK
188	 */
189	public function write_header($outputlangs)
190	{
191		// phpcs:enable
192		return 0;
193	}
194
195
196	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
197	/**
198	 *  Output title line into file
199	 *
200	 *  @param      array		$array_export_fields_label   	Array with list of label of fields
201	 *  @param      array		$array_selected_sorted       	Array with list of field to export
202	 *  @param      Translate	$outputlangs    				Object lang to translate values
203	 *  @param		array		$array_types					Array with types of fields
204	 * 	@return		int											<0 if KO, >0 if OK
205	 */
206	public function write_title($array_export_fields_label, $array_selected_sorted, $outputlangs, $array_types)
207	{
208		// phpcs:enable
209		foreach ($array_selected_sorted as $code => $value)
210		{
211			$newvalue = $outputlangs->transnoentities($array_export_fields_label[$code]); // newvalue is now $outputlangs->charset_output encoded
212			$newvalue = $this->tsv_clean($newvalue, $outputlangs->charset_output);
213
214			fwrite($this->handle, $newvalue.$this->separator);
215		}
216		fwrite($this->handle, "\n");
217		return 0;
218	}
219
220
221	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
222	/**
223	 * 	Output record line into file
224	 *
225	 *  @param      array		$array_selected_sorted      Array with list of field to export
226	 *  @param      resource	$objp                       A record from a fetch with all fields from select
227	 *  @param      Translate	$outputlangs                Object lang to translate values
228	 *  @param		array		$array_types				Array with types of fields
229	 * 	@return		int										<0 if KO, >0 if OK
230	 */
231	public function write_record($array_selected_sorted, $objp, $outputlangs, $array_types)
232	{
233		// phpcs:enable
234		global $conf;
235
236		$this->col = 0;
237 		foreach ($array_selected_sorted as $code => $value)
238		{
239			if (strpos($code, ' as ') == 0) $alias = str_replace(array('.', '-', '(', ')'), '_', $code);
240			else $alias = substr($code, strpos($code, ' as ') + 4);
241			if (empty($alias)) dol_print_error('', 'Bad value for field with code='.$code.'. Try to redefine export.');
242
243			$newvalue = $outputlangs->convToOutputCharset($objp->$alias); // objp->$alias must be utf8 encoded as any var in memory // newvalue is now $outputlangs->charset_output encoded
244			$typefield = isset($array_types[$code]) ? $array_types[$code] : '';
245
246			// Translation newvalue
247			if (preg_match('/^\((.*)\)$/i', $newvalue, $reg)) $newvalue = $outputlangs->transnoentities($reg[1]);
248
249			$newvalue = $this->tsv_clean($newvalue, $outputlangs->charset_output);
250
251			if (preg_match('/^Select:/i', $typefield, $reg) && $typefield = substr($typefield, 7))
252			{
253				$array = unserialize($typefield);
254				$array = $array['options'];
255				$newvalue = $array[$newvalue];
256			}
257
258			fwrite($this->handle, $newvalue.$this->separator);
259			$this->col++;
260		}
261		fwrite($this->handle, "\n");
262		return 0;
263	}
264
265	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
266	/**
267	 * 	Output footer into file
268	 *
269	 * 	@param		Translate	$outputlangs		Output language object
270	 * 	@return		int								<0 if KO, >0 if OK
271	 */
272	public function write_footer($outputlangs)
273	{
274		// phpcs:enable
275		return 0;
276	}
277
278	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
279	/**
280	 * 	Close file handle
281	 *
282	 * 	@return		int							<0 if KO, >0 if OK
283	 */
284	public function close_file()
285	{
286		// phpcs:enable
287		fclose($this->handle);
288		return 0;
289	}
290
291	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
292	/**
293	 * Clean a cell to respect rules of TSV file cells
294	 *
295	 * @param 	string	$newvalue	String to clean
296	 * @param	string	$charset	Input AND Output character set
297	 * @return 	string				Value cleaned
298	 */
299	public function tsv_clean($newvalue, $charset)
300	{
301		// phpcs:enable
302		// Rule Dolibarr: No HTML
303		$newvalue = dol_string_nohtmltag($newvalue, 1, $charset);
304
305		// Rule 1 TSV: No CR, LF in cells
306		$newvalue = str_replace("\r", '', $newvalue);
307		$newvalue = str_replace("\n", '\n', $newvalue);
308
309		// Rule 2 TSV: If value contains tab, we must replace by space
310		if (preg_match('/'.$this->separator.'/', $newvalue)) {
311			$newvalue = str_replace("\t", " ", $newvalue);
312		}
313
314		return $newvalue;
315	}
316}
317