1<?php
2/* Copyright (C) 2007-2012  Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2014-2016  Juanjo Menent       <jmenent@2byte.es>
4 * Copyright (C) 2015       Florian Henry       <florian.henry@open-concept.pro>
5 * Copyright (C) 2015       Raphaël Doursenaud  <rdoursenaud@gpcsolutions.fr>
6 * Copyright (C) 2018       Francis Appels      <francis.appels@yahoo.com>
7 * Copyright (C) 2019       Frédéric France     <frederic.france@netlogic.fr>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23/**
24 * \file    htdocs/ecm/class/ecmfiles.class.php
25 * \ingroup ecm
26 * \brief   Class to manage ECM Files (Create/Read/Update/Delete)
27 */
28
29// Put here all includes required by your class file
30require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
31
32/**
33 * Class to manage ECM files
34 */
35class EcmFiles extends CommonObject
36{
37	/**
38	 * @var string Id to identify managed objects
39	 */
40	public $element = 'ecmfiles';
41
42	/**
43	 * @var string Name of table without prefix where object is stored
44	 */
45	public $table_element = 'ecm_files';
46
47	/**
48	 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
49	 */
50	public $picto = 'folder-open';
51
52	/**
53	 * @var string Ref hash of file path
54	 */
55	public $ref;
56
57	/**
58	 * hash of file content (md5_file(dol_osencode($destfull))
59	 * @var string Ecm Files label
60	 */
61	public $label;
62
63	/**
64	 * @var string hash for file sharing, empty by default (example: getRandomPassword(true))
65	 */
66	public $share;
67
68	/**
69	 * @var int Entity
70	 */
71	public $entity;
72
73	/**
74	 * @var string filename, Note: Into ecm database record, the entry $filename never ends with .noexe
75	 */
76	public $filename;
77
78	/**
79	 * @var string filepath
80	 */
81	public $filepath;
82
83	/**
84	 * @var string fullpath origin
85	 */
86	public $fullpath_orig;
87
88	/**
89	 * @var string description
90	 */
91	public $description;
92
93	/**
94	 * @var string keywords
95	 */
96	public $keywords;
97
98	/**
99	 * @var string cover
100	 */
101	public $cover;
102
103	/**
104	 * @var int position
105	 */
106	public $position;
107
108	/**
109	 * @var string can be 'generated', 'uploaded', 'unknown'
110	 */
111	public $gen_or_uploaded;
112
113	/**
114	 * @var string extraparams
115	 */
116	public $extraparams;
117
118	/**
119	 * @var int|string date create
120	 */
121	public $date_c = '';
122
123	/**
124	 * @var int|string date modify
125	 */
126	public $date_m = '';
127
128	/**
129	 * @var int ID
130	 */
131	public $fk_user_c;
132
133	/**
134	 * @var int ID
135	 */
136	public $fk_user_m;
137
138	/**
139	 * @var string acl
140	 */
141	public $acl;
142
143	/**
144	 * @var string src object type
145	 */
146	public $src_object_type;
147
148	/**
149	 * @var int src object id
150	 */
151	public $src_object_id;
152
153	/**
154	 * @var int section_id		ID of section = ID of EcmDirectory, directory of manual ECM (not stored into database)
155	 */
156	public $section_id;
157
158
159
160	/**
161	 * Constructor
162	 *
163	 * @param DoliDb $db Database handler
164	 */
165	public function __construct(DoliDB $db)
166	{
167		$this->db = $db;
168	}
169
170	/**
171	 * Create object into database
172	 *
173	 * @param  User $user      	User that creates
174	 * @param  bool $notrigger 	false=launch triggers after, true=disable triggers
175	 * @return int 				<0 if KO, Id of created object if OK
176	 */
177	public function create(User $user, $notrigger = false)
178	{
179		global $conf;
180
181		dol_syslog(__METHOD__, LOG_DEBUG);
182
183		$error = 0;
184
185		// Clean parameters
186		if (isset($this->ref)) {
187			$this->ref = trim($this->ref);
188		}
189		if (isset($this->label)) {
190			$this->label = trim($this->label);
191		}
192		if (isset($this->share)) {
193			$this->share = trim($this->share);
194		}
195		if (isset($this->entity)) {
196			$this->entity = (int) $this->entity;
197		}
198		if (isset($this->filename)) {
199			$this->filename = preg_replace('/\.noexe$/', '', trim($this->filename));
200		}
201		if (isset($this->filepath)) {
202			$this->filepath = trim($this->filepath);
203			$this->filepath = preg_replace('/[\\/]+$/', '', $this->filepath); // Remove last /
204		}
205		if (isset($this->fullpath_orig)) {
206			$this->fullpath_orig = trim($this->fullpath_orig);
207		}
208		if (isset($this->description)) {
209			$this->description = trim($this->description);
210		}
211		if (isset($this->keywords)) {
212			$this->keywords = trim($this->keywords);
213		}
214		if (isset($this->cover)) {
215			$this->cover = trim($this->cover);
216		}
217		if (isset($this->gen_or_uploaded)) {
218			$this->gen_or_uploaded = trim($this->gen_or_uploaded);
219		}
220		if (isset($this->extraparams)) {
221			$this->extraparams = trim($this->extraparams);
222		}
223		if (isset($this->fk_user_c)) {
224			$this->fk_user_c = (int) $this->fk_user_c;
225		}
226		if (isset($this->fk_user_m)) {
227			$this->fk_user_m = (int) $this->fk_user_m;
228		}
229		if (isset($this->acl)) {
230			$this->acl = trim($this->acl);
231		}
232		if (isset($this->src_object_type)) {
233			$this->src_object_type = trim($this->src_object_type);
234		}
235		if (empty($this->date_c)) {
236			$this->date_c = dol_now();
237		}
238		if (empty($this->date_m)) {
239			$this->date_m = dol_now();
240		}
241
242		// If ref not defined
243		$ref = '';
244		if (!empty($this->ref)) {
245			$ref = $this->ref;
246		} else {
247			include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
248			$ref = dol_hash($this->filepath.'/'.$this->filename, 3);
249		}
250
251		$maxposition = 0;
252		if (empty($this->position)) {
253			// Get max used
254			$sql = "SELECT MAX(position) as maxposition FROM ".MAIN_DB_PREFIX.$this->table_element;
255			$sql .= " WHERE filepath ='".$this->db->escape($this->filepath)."'";
256
257			$resql = $this->db->query($sql);
258			if ($resql) {
259				$obj = $this->db->fetch_object($resql);
260				$maxposition = (int) $obj->maxposition;
261			} else {
262				$this->errors[] = 'Error '.$this->db->lasterror();
263				return --$error;
264			}
265			$maxposition = $maxposition + 1;
266		} else {
267			$maxposition = $this->position;
268		}
269
270		// Check parameters
271		if (empty($this->filename) || empty($this->filepath)) {
272			$this->errors[] = 'Bad property filename or filepath';
273			return --$error;
274		}
275		if (!isset($this->entity)) {
276			$this->entity = $conf->entity;
277		}
278		// Put here code to add control on parameters values
279
280		// Insert request
281		$sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.'(';
282		$sql .= 'ref,';
283		$sql .= 'label,';
284		$sql .= 'share,';
285		$sql .= 'entity,';
286		$sql .= 'filename,';
287		$sql .= 'filepath,';
288		$sql .= 'fullpath_orig,';
289		$sql .= 'description,';
290		$sql .= 'keywords,';
291		$sql .= 'cover,';
292		$sql .= 'position,';
293		$sql .= 'gen_or_uploaded,';
294		$sql .= 'extraparams,';
295		$sql .= 'date_c,';
296		$sql .= 'tms,';
297		$sql .= 'fk_user_c,';
298		$sql .= 'fk_user_m,';
299		$sql .= 'acl,';
300		$sql .= 'src_object_type,';
301		$sql .= 'src_object_id';
302		$sql .= ') VALUES (';
303		$sql .= " '".$this->db->escape($ref)."', ";
304		$sql .= ' '.(!isset($this->label) ? 'NULL' : "'".$this->db->escape($this->label)."'").',';
305		$sql .= ' '.(!isset($this->share) ? 'NULL' : "'".$this->db->escape($this->share)."'").',';
306		$sql .= ' '.$this->entity.',';
307		$sql .= ' '.(!isset($this->filename) ? 'NULL' : "'".$this->db->escape($this->filename)."'").',';
308		$sql .= ' '.(!isset($this->filepath) ? 'NULL' : "'".$this->db->escape($this->filepath)."'").',';
309		$sql .= ' '.(!isset($this->fullpath_orig) ? 'NULL' : "'".$this->db->escape($this->fullpath_orig)."'").',';
310		$sql .= ' '.(!isset($this->description) ? 'NULL' : "'".$this->db->escape($this->description)."'").',';
311		$sql .= ' '.(!isset($this->keywords) ? 'NULL' : "'".$this->db->escape($this->keywords)."'").',';
312		$sql .= ' '.(!isset($this->cover) ? 'NULL' : "'".$this->db->escape($this->cover)."'").',';
313		$sql .= ' '.$maxposition.',';
314		$sql .= ' '.(!isset($this->gen_or_uploaded) ? 'NULL' : "'".$this->db->escape($this->gen_or_uploaded)."'").',';
315		$sql .= ' '.(!isset($this->extraparams) ? 'NULL' : "'".$this->db->escape($this->extraparams)."'").',';
316		$sql .= ' '."'".$this->db->idate($this->date_c)."'".',';
317		$sql .= ' '.(!isset($this->date_m) || dol_strlen($this->date_m) == 0 ? 'NULL' : "'".$this->db->idate($this->date_m)."'").',';
318		$sql .= ' '.(!isset($this->fk_user_c) ? $user->id : $this->fk_user_c).',';
319		$sql .= ' '.(!isset($this->fk_user_m) ? 'NULL' : $this->fk_user_m).',';
320		$sql .= ' '.(!isset($this->acl) ? 'NULL' : "'".$this->db->escape($this->acl)."'").',';
321		$sql .= ' '.(!isset($this->src_object_type) ? 'NULL' : "'".$this->db->escape($this->src_object_type)."'").',';
322		$sql .= ' '.(!isset($this->src_object_id) ? 'NULL' : $this->src_object_id);
323		$sql .= ')';
324
325		$this->db->begin();
326
327		$resql = $this->db->query($sql);
328		if (!$resql) {
329			$error++;
330			$this->errors[] = 'Error '.$this->db->lasterror();
331			dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
332		}
333
334		if (!$error) {
335			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
336			$this->position = $maxposition;
337
338			// Triggers
339			if (!$notrigger) {
340				// Call triggers
341				$result = $this->call_trigger(strtoupper(get_class($this)).'_CREATE', $user);
342				if ($result < 0) {
343					$error++;
344				}
345				// End call triggers
346			}
347		}
348
349		// Commit or rollback
350		if ($error) {
351			$this->db->rollback();
352
353			return -1 * $error;
354		} else {
355			$this->db->commit();
356
357			return $this->id;
358		}
359	}
360
361	/**
362	 * Load object in memory from the database
363	 *
364	 * @param  int    $id          	   	Id object
365	 * @param  string $ref         	   	Hash of file name (filename+filepath). Not always defined on some version.
366	 * @param  string $relativepath    	Relative path of file from document directory. Example: 'path/path2/file' or 'path/path2/*'
367	 * @param  string $hashoffile      	Hash of file content. Take the first one found if same file is at different places. This hash will also change if file content is changed.
368	 * @param  string $hashforshare    	Hash of file sharing.
369	 * @param  string $src_object_type 	src_object_type to search (value of object->table_element)
370	 * @param  string $src_object_id 	src_object_id to search
371	 * @return int                 	   	<0 if KO, 0 if not found, >0 if OK
372	 */
373	public function fetch($id, $ref = '', $relativepath = '', $hashoffile = '', $hashforshare = '', $src_object_type = '', $src_object_id = 0)
374	{
375		global $conf;
376
377		dol_syslog(__METHOD__, LOG_DEBUG);
378
379		$sql = 'SELECT';
380		$sql .= ' t.rowid,';
381		$sql .= " t.ref,";
382		$sql .= " t.label,";
383		$sql .= " t.share,";
384		$sql .= " t.entity,";
385		$sql .= " t.filename,";
386		$sql .= " t.filepath,";
387		$sql .= " t.fullpath_orig,";
388		$sql .= " t.description,";
389		$sql .= " t.keywords,";
390		$sql .= " t.cover,";
391		$sql .= " t.position,";
392		$sql .= " t.gen_or_uploaded,";
393		$sql .= " t.extraparams,";
394		$sql .= " t.date_c,";
395		$sql .= " t.tms as date_m,";
396		$sql .= " t.fk_user_c,";
397		$sql .= " t.fk_user_m,";
398		$sql .= ' t.note_private,';
399		$sql .= ' t.note_public,';
400		$sql .= " t.acl,";
401		$sql .= " t.src_object_type,";
402		$sql .= " t.src_object_id";
403		$sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
404		$sql .= ' WHERE 1 = 1';
405		/* Fetching this table depends on filepath+filename, it must not depends on entity because filesystem on disk does not know what is Dolibarr entities
406		 if (! empty($conf->multicompany->enabled)) {
407		 $sql .= " AND entity IN (" . getEntity('ecmfiles') . ")";
408		 }*/
409		if ($relativepath) {
410			$relativepathwithnoexe = preg_replace('/\.noexe$/', '', $relativepath); // We must never have the .noexe into the database
411			$sql .= " AND t.filepath = '".$this->db->escape(dirname($relativepath))."'";
412			$filename = basename($relativepathwithnoexe);
413			if ($filename != '*') {
414				$sql .= " AND t.filename = '".$this->db->escape($filename)."'";
415			}
416			$sql .= " AND t.entity = ".$conf->entity; // unique key include the entity so each company has its own index
417		} elseif (!empty($ref)) {		// hash of file path
418			$sql .= " AND t.ref = '".$this->db->escape($ref)."'";
419			$sql .= " AND t.entity = ".$conf->entity; // unique key include the entity so each company has its own index
420		} elseif (!empty($hashoffile)) {	// hash of content
421			$sql .= " AND t.label = '".$this->db->escape($hashoffile)."'";
422			$sql .= " AND t.entity = ".$conf->entity; // unique key include the entity so each company has its own index
423		} elseif (!empty($hashforshare)) {
424			$sql .= " AND t.share = '".$this->db->escape($hashforshare)."'";
425			//$sql .= " AND t.entity = ".$conf->entity;							// hashforshare already unique
426		} elseif ($src_object_type && $src_object_id) {
427			// Warning: May return several record, and only first one is returned !
428			$sql .= " AND t.src_object_type = '".$this->db->escape($src_object_type)."' AND t.src_object_id = ".((int) $src_object_id);
429			$sql .= " AND t.entity = ".$conf->entity;
430		} else {
431			$sql .= ' AND t.rowid = '.((int) $id); // rowid already unique
432		}
433
434		$this->db->plimit(1); // When we search on src or on hash of content (hashforfile) to solve hash conflict when several files has same content, we take first one only
435		$this->db->order('t.rowid', 'ASC');
436
437		$resql = $this->db->query($sql);
438		if ($resql) {
439			$numrows = $this->db->num_rows($resql);
440			if ($numrows) {
441				$obj = $this->db->fetch_object($resql);
442
443				$this->id = $obj->rowid;
444				$this->ref = $obj->ref;
445				$this->label = $obj->label;
446				$this->share = $obj->share;
447				$this->entity = $obj->entity;
448				$this->filename = $obj->filename;
449				$this->filepath = $obj->filepath;
450				$this->fullpath_orig = $obj->fullpath_orig;
451				$this->description = $obj->description;
452				$this->keywords = $obj->keywords;
453				$this->cover = $obj->cover;
454				$this->position = $obj->position;
455				$this->gen_or_uploaded = $obj->gen_or_uploaded;
456				$this->extraparams = $obj->extraparams;
457				$this->date_c = $this->db->jdate($obj->date_c);
458				$this->date_m = $this->db->jdate($obj->date_m);
459				$this->fk_user_c = $obj->fk_user_c;
460				$this->fk_user_m = $obj->fk_user_m;
461				$this->note_private = $obj->note_private;
462				$this->note_public = $obj->note_public;
463				$this->acl = $obj->acl;
464				$this->src_object_type = $obj->src_object_type;
465				$this->src_object_id = $obj->src_object_id;
466			}
467
468			// Retrieve all extrafields for ecm_files
469			// fetch optionals attributes and labels
470			$this->fetch_optionals();
471
472			// $this->fetch_lines();
473
474			$this->db->free($resql);
475
476			if ($numrows) {
477				return 1;
478			} else {
479				return 0;
480			}
481		} else {
482			$this->errors[] = 'Error '.$this->db->lasterror();
483			dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
484
485			return -1;
486		}
487	}
488
489	/**
490	 * Load object in memory from the database
491	 *
492	 * @param string $sortorder Sort Order
493	 * @param string $sortfield Sort field
494	 * @param int    $limit     offset limit
495	 * @param int    $offset    offset limit
496	 * @param array  $filter    filter array
497	 * @param string $filtermode filter mode (AND or OR)
498	 *
499	 * @return int <0 if KO, >0 if OK
500	 */
501	public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
502	{
503		dol_syslog(__METHOD__, LOG_DEBUG);
504
505		$sql = 'SELECT';
506		$sql .= ' t.rowid,';
507		$sql .= " t.label,";
508		$sql .= " t.share,";
509		$sql .= " t.entity,";
510		$sql .= " t.filename,";
511		$sql .= " t.filepath,";
512		$sql .= " t.fullpath_orig,";
513		$sql .= " t.description,";
514		$sql .= " t.keywords,";
515		$sql .= " t.cover,";
516		$sql .= " t.position,";
517		$sql .= " t.gen_or_uploaded,";
518		$sql .= " t.extraparams,";
519		$sql .= " t.date_c,";
520		$sql .= " t.tms as date_m,";
521		$sql .= " t.fk_user_c,";
522		$sql .= " t.fk_user_m,";
523		$sql .= " t.acl,";
524		$sql .= " t.src_object_type,";
525		$sql .= " t.src_object_id";
526		$sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
527
528		// Manage filter
529		$sqlwhere = array();
530		if (count($filter) > 0) {
531			foreach ($filter as $key => $value) {
532				if ($key == 't.src_object_id') {
533					$sqlwhere[] = $key.' = '.((int) $value);
534				} else {
535					$sqlwhere[] = $key.' LIKE \'%'.$this->db->escape($value).'%\'';
536				}
537			}
538		}
539		$sql .= ' WHERE 1 = 1';
540		/* Fetching this table depends on filepath+filename, it must not depends on entity
541		 if (! empty($conf->multicompany->enabled)) {
542		 $sql .= " AND entity IN (" . getEntity('ecmfiles') . ")";
543		 }*/
544		if (count($sqlwhere) > 0) {
545			$sql .= ' AND '.implode(' '.$filtermode.' ', $sqlwhere);
546		}
547		if (!empty($sortfield)) {
548			$sql .= $this->db->order($sortfield, $sortorder);
549		}
550		if (!empty($limit)) {
551			$sql .= ' '.$this->db->plimit($limit, $offset);
552		}
553
554		$this->lines = array();
555
556		$resql = $this->db->query($sql);
557		if ($resql) {
558			$num = $this->db->num_rows($resql);
559
560			while ($obj = $this->db->fetch_object($resql)) {
561				$line = new EcmfilesLine();
562
563				$line->id = $obj->rowid;
564				$line->ref = $obj->ref;
565				$line->label = $obj->label;
566				$line->share = $obj->share;
567				$line->entity = $obj->entity;
568				$line->filename = $obj->filename;
569				$line->filepath = $obj->filepath;
570				$line->fullpath_orig = $obj->fullpath_orig;
571				$line->description = $obj->description;
572				$line->keywords = $obj->keywords;
573				$line->cover = $obj->cover;
574				$line->position = $obj->position;
575				$line->gen_or_uploaded = $obj->gen_or_uploaded;
576				$line->extraparams = $obj->extraparams;
577				$line->date_c = $this->db->jdate($obj->date_c);
578				$line->date_m = $this->db->jdate($obj->date_m);
579				$line->fk_user_c = $obj->fk_user_c;
580				$line->fk_user_m = $obj->fk_user_m;
581				$line->acl = $obj->acl;
582				$line->src_object_type = $obj->src_object_type;
583				$line->src_object_id = $obj->src_object_id;
584				$this->lines[] = $line;
585			}
586			$this->db->free($resql);
587
588			return $num;
589		} else {
590			$this->errors[] = 'Error '.$this->db->lasterror();
591			dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
592
593			return -1;
594		}
595	}
596
597	/**
598	 * Update object into database
599	 *
600	 * @param  User $user      User that modifies
601	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
602	 *
603	 * @return int <0 if KO, >0 if OK
604	 */
605	public function update(User $user, $notrigger = false)
606	{
607		global $conf;
608
609		$error = 0;
610
611		dol_syslog(__METHOD__, LOG_DEBUG);
612
613		// Clean parameters
614
615		if (isset($this->ref)) {
616			$this->ref = trim($this->ref);
617		}
618		if (isset($this->label)) {
619			$this->label = trim($this->label);
620		}
621		if (isset($this->share)) {
622			$this->share = trim($this->share);
623		}
624		if (isset($this->entity)) {
625			$this->entity = trim($this->entity);
626		}
627		if (isset($this->filename)) {
628			$this->filename = preg_replace('/\.noexe$/', '', trim($this->filename));
629		}
630		if (isset($this->filepath)) {
631			$this->filepath = trim($this->filepath);
632			$this->filepath = preg_replace('/[\\/]+$/', '', $this->filepath); // Remove last /
633		}
634		if (isset($this->fullpath_orig)) {
635			$this->fullpath_orig = trim($this->fullpath_orig);
636		}
637		if (isset($this->description)) {
638			$this->description = trim($this->description);
639		}
640		if (isset($this->keywords)) {
641			$this->keywords = trim($this->keywords);
642		}
643		if (isset($this->cover)) {
644			$this->cover = trim($this->cover);
645		}
646		if (isset($this->gen_or_uploaded)) {
647			$this->gen_or_uploaded = trim($this->gen_or_uploaded);
648		}
649		if (isset($this->extraparams)) {
650			$this->extraparams = trim($this->extraparams);
651		}
652		if (isset($this->fk_user_m)) {
653			$this->fk_user_m = trim($this->fk_user_m);
654		}
655		if (isset($this->acl)) {
656			$this->acl = trim($this->acl);
657		}
658		if (isset($this->src_object_type)) {
659			$this->src_object_type = trim($this->src_object_type);
660		}
661
662		// Check parameters
663		// Put here code to add a control on parameters values
664
665		// Update request
666		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET';
667		$sql .= " ref = '".dol_hash($this->filepath.'/'.$this->filename, 3)."',";
668		$sql .= ' label = '.(isset($this->label) ? "'".$this->db->escape($this->label)."'" : "null").',';
669		$sql .= ' share = '.(!empty($this->share) ? "'".$this->db->escape($this->share)."'" : "null").',';
670		$sql .= ' entity = '.(isset($this->entity) ? $this->entity : $conf->entity).',';
671		$sql .= ' filename = '.(isset($this->filename) ? "'".$this->db->escape($this->filename)."'" : "null").',';
672		$sql .= ' filepath = '.(isset($this->filepath) ? "'".$this->db->escape($this->filepath)."'" : "null").',';
673		$sql .= ' fullpath_orig = '.(isset($this->fullpath_orig) ? "'".$this->db->escape($this->fullpath_orig)."'" : "null").',';
674		$sql .= ' description = '.(isset($this->description) ? "'".$this->db->escape($this->description)."'" : "null").',';
675		$sql .= ' keywords = '.(isset($this->keywords) ? "'".$this->db->escape($this->keywords)."'" : "null").',';
676		$sql .= ' cover = '.(isset($this->cover) ? "'".$this->db->escape($this->cover)."'" : "null").',';
677		$sql .= ' position = '.(isset($this->position) ? $this->db->escape($this->position) : "0").',';
678		$sql .= ' gen_or_uploaded = '.(isset($this->gen_or_uploaded) ? "'".$this->db->escape($this->gen_or_uploaded)."'" : "null").',';
679		$sql .= ' extraparams = '.(isset($this->extraparams) ? "'".$this->db->escape($this->extraparams)."'" : "null").',';
680		$sql .= ' date_c = '.(!isset($this->date_c) || dol_strlen($this->date_c) != 0 ? "'".$this->db->idate($this->date_c)."'" : 'null').',';
681		//$sql .= ' tms = '.(! isset($this->date_m) || dol_strlen($this->date_m) != 0 ? "'".$this->db->idate($this->date_m)."'" : 'null').','; // Field automatically updated
682		$sql .= ' fk_user_m = '.($this->fk_user_m > 0 ? $this->fk_user_m : $user->id).',';
683		$sql .= ' acl = '.(isset($this->acl) ? "'".$this->db->escape($this->acl)."'" : "null").',';
684		$sql .= ' src_object_id = '.($this->src_object_id > 0 ? $this->src_object_id : "null").',';
685		$sql .= ' src_object_type = '.(isset($this->src_object_type) ? "'".$this->db->escape($this->src_object_type)."'" : "null");
686		$sql .= ' WHERE rowid='.((int) $this->id);
687
688		$this->db->begin();
689
690		$resql = $this->db->query($sql);
691		if (!$resql) {
692			$error++;
693			$this->errors[] = 'Error '.$this->db->lasterror();
694			dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
695		}
696
697		// Triggers
698		if (!$error && !$notrigger) {
699			// Call triggers
700			$result = $this->call_trigger(strtoupper(get_class($this)).'_MODIFY', $user);
701			if ($result < 0) {
702				$error++;
703			} //Do also here what you must do to rollback action if trigger fail
704			// End call triggers
705		}
706
707		// Commit or rollback
708		if ($error) {
709			$this->db->rollback();
710
711			return -1 * $error;
712		} else {
713			$this->db->commit();
714
715			return 1;
716		}
717	}
718
719	/**
720	 * Delete object in database
721	 *
722	 * @param User $user      User that deletes
723	 * @param bool $notrigger false=launch triggers after, true=disable triggers
724	 *
725	 * @return int <0 if KO, >0 if OK
726	 */
727	public function delete(User $user, $notrigger = false)
728	{
729		dol_syslog(__METHOD__, LOG_DEBUG);
730
731		$error = 0;
732
733		$this->db->begin();
734
735		// Triggers
736		if (!$notrigger) {
737			// Call triggers
738			$result = $this->call_trigger(strtoupper(get_class($this)).'_DELETE', $user);
739			if ($result < 0) {
740				$error++;
741			} //Do also here what you must do to rollback action if trigger fail
742			// End call triggers
743		}
744
745		// If you need to delete child tables to, you can insert them here
746
747		if (!$error) {
748			$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element;
749			$sql .= ' WHERE rowid='.((int) $this->id);
750
751			$resql = $this->db->query($sql);
752			if (!$resql) {
753				$error++;
754				$this->errors[] = 'Error '.$this->db->lasterror();
755				dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
756			}
757		}
758
759		// Commit or rollback
760		if ($error) {
761			$this->db->rollback();
762
763			return -1 * $error;
764		} else {
765			$this->db->commit();
766
767			return 1;
768		}
769	}
770
771	/**
772	 * Load an object from its id and create a new one in database
773	 *
774	 * @param	User	$user		User making the clone
775	 * @param   int     $fromid     Id of object to clone
776	 * @return  int                 New id of clone
777	 */
778	public function createFromClone(User $user, $fromid)
779	{
780		dol_syslog(__METHOD__, LOG_DEBUG);
781
782		$error = 0;
783		$object = new Ecmfiles($this->db);
784
785		$this->db->begin();
786
787		// Load source object
788		$object->fetch($fromid);
789		// Reset object
790		$object->id = 0;
791
792		// Clear fields
793		// ...
794
795		// Create clone
796		$object->context['createfromclone'] = 'createfromclone';
797		$result = $object->create($user);
798
799		// Other options
800		if ($result < 0) {
801			$error++;
802			$this->errors = $object->errors;
803			dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
804		}
805
806		unset($object->context['createfromclone']);
807
808		// End
809		if (!$error) {
810			$this->db->commit();
811
812			return $object->id;
813		} else {
814			$this->db->rollback();
815
816			return -1;
817		}
818	}
819
820	/**
821	 *  Return a link to the object card (with optionaly the picto)
822	 *
823	 *	@param	int		$withpicto			Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
824	 *	@param	string	$option				On what the link point to
825	 *  @param	int  	$notooltip			1=Disable tooltip
826	 *  @param	int		$maxlen				Max length of visible user name
827	 *  @param  string  $morecss            Add more css on link
828	 *	@return	string						String with URL
829	 */
830	public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $maxlen = 24, $morecss = '')
831	{
832		global $db, $conf, $langs;
833		global $dolibarr_main_authentication, $dolibarr_main_demo;
834		global $menumanager;
835
836		if (!empty($conf->dol_no_mouse_hover)) {
837			$notooltip = 1; // Force disable tooltips
838		}
839
840		$result = '';
841
842		$label = '<u>'.$langs->trans("MyModule").'</u>';
843		$label .= '<br>';
844		$label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
845
846		$url = DOL_URL_ROOT.'/ecm/'.$this->table_name.'_card.php?id='.$this->id;
847
848		$linkclose = '';
849		if (empty($notooltip)) {
850			if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
851				$label = $langs->trans("ShowProject");
852				$linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
853			}
854			$linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
855			$linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
856		} else {
857			$linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
858		}
859
860		$linkstart = '<a href="'.$url.'"';
861		$linkstart .= $linkclose.'>';
862		$linkend = '</a>';
863
864		if ($withpicto) {
865			$result .= ($linkstart.img_object(($notooltip ? '' : $label), 'label', ($notooltip ? '' : 'class="classfortooltip"')).$linkend);
866			if ($withpicto != 2) {
867				$result .= ' ';
868			}
869		}
870		$result .= $linkstart.$this->ref.$linkend;
871		return $result;
872	}
873
874	/**
875	 *  Retourne le libelle du status d'un user (actif, inactif)
876	 *
877	 *  @param	int		$mode          0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
878	 *  @return	string 			       Label of status
879	 */
880	public function getLibStatut($mode = 0)
881	{
882		return $this->LibStatut($this->status, $mode);
883	}
884
885	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
886	/**
887	 *  Return the status
888	 *
889	 *  @param	int		$status        	Id status
890	 *  @param  int		$mode          	0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 5=Long label + Picto
891	 *  @return string 			       	Label of status
892	 */
893	public static function LibStatut($status, $mode = 0)
894	{
895		// phpcs:enable
896		global $langs;
897		return '';
898	}
899
900
901	/**
902	 * Initialise object with example values
903	 * Id must be 0 if object instance is a specimen
904	 *
905	 * @return void
906	 */
907	public function initAsSpecimen()
908	{
909		global $conf, $user;
910
911		$this->id = 0;
912		$this->specimen = 1;
913		$this->label = '0a1b2c3e4f59999999';
914		$this->entity = 1;
915		$this->filename = 'myspecimenfilefile.pdf';
916		$this->filepath = '/aaa/bbb';
917		$this->fullpath_orig = 'c:/file on my disk.pdf';
918		$this->description = 'This is a long description of file';
919		$this->keywords = 'key1,key2';
920		$this->cover = '1';
921		$this->position = 5;
922		$this->gen_or_uploaded = 'uploaded';
923		$this->extraparams = '';
924		$this->date_c = (dol_now() - 3600 * 24 * 10);
925		$this->date_m = '';
926		$this->fk_user_c = $user->id;
927		$this->fk_user_m = '';
928		$this->acl = '';
929		$this->src_object_type = 'product';
930		$this->src_object_id = 1;
931	}
932}
933
934
935/**
936 * Class of an index line of a document
937 */
938class EcmfilesLine
939{
940	/**
941	 * @var string ECM files line label
942	 */
943	public $label;
944
945	/**
946	 * @var int Entity
947	 */
948	public $entity;
949
950	public $filename;
951	public $filepath;
952	public $fullpath_orig;
953
954	/**
955	 * @var string description
956	 */
957	public $description;
958
959	public $keywords;
960	public $cover;
961	public $position;
962	public $gen_or_uploaded; // can be 'generated', 'uploaded', 'unknown'
963	public $extraparams;
964	public $date_c = '';
965	public $date_m = '';
966
967	/**
968	 * @var int ID
969	 */
970	public $fk_user_c;
971
972	/**
973	 * @var int ID
974	 */
975	public $fk_user_m;
976
977	public $acl;
978	public $src_object_type;
979	public $src_object_id;
980}
981