dolibarr 21.0.0-alpha
knowledgerecord.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
4 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
26// Put here all includes required by your class file
27require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
28//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
29//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
30
35{
39 public $module = 'knowledgemanagement';
40
44 public $element = 'knowledgerecord';
45
49 public $table_element = 'knowledgemanagement_knowledgerecord';
50
54 public $picto = 'knowledgemanagement';
55
56
57 const STATUS_DRAFT = 0;
58 const STATUS_VALIDATED = 1;
59 const STATUS_CANCELED = 9;
60
61
89 // BEGIN MODULEBUILDER PROPERTIES
93 public $fields = array(
94 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'position' => 1, 'notnull' => 1, 'visible' => 0, 'noteditable' => 1, 'index' => 1, 'css' => 'left', 'comment' => "Id"),
95 'ref' => array('type' => 'varchar(128)', 'label' => 'Ref', 'enabled' => 1, 'position' => 10, 'notnull' => 1, 'default' => '(PROV)', 'visible' => 5, 'index' => 1, 'searchall' => 1, 'comment' => "Reference of object", "csslist" => "nowraponall", "showoncombobox" => 1),
96 'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => '1', 'enabled' => 1, 'visible' => 0, 'notnull' => 1, 'position' => 20, 'index' => 1),
97 'question' => array('type' => 'text', 'label' => 'Question', 'enabled' => 1, 'position' => 30, 'notnull' => 1, 'visible' => 1, 'searchall' => 1, 'csslist' => 'tdoverflowmax300 small', 'copytoclipboard' => 1, 'tdcss' => 'titlefieldcreate nowraponall'),
98 'lang' => array('type' => 'varchar(6)', 'label' => 'Language', 'enabled' => 1, 'position' => 40, 'notnull' => 0, 'visible' => 1, 'tdcss' => 'titlefieldcreate nowraponall', "csslist" => "minwidth100 maxwidth200"),
99 'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'position' => 500, 'notnull' => 1, 'visible' => -2, 'csslist' => 'nowraponall'),
100 'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'position' => 501, 'notnull' => 0, 'visible' => 2,),
101 'last_main_doc' => array('type' => 'varchar(255)', 'label' => 'LastMainDoc', 'enabled' => 1, 'position' => 600, 'notnull' => 0, 'visible' => 0,),
102 'fk_user_creat' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserCreation', 'enabled' => 1, 'position' => 510, 'notnull' => 1, 'visible' => -2, 'foreignkey' => 'user.rowid',),
103 'fk_user_modif' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'position' => 511, 'notnull' => -1, 'visible' => -2,),
104 'fk_user_valid' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserValidation', 'enabled' => 1, 'position' => 512, 'notnull' => 0, 'visible' => -2,),
105 'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'position' => 1000, 'notnull' => -1, 'visible' => -2,),
106 'model_pdf' => array('type' => 'varchar(255)', 'label' => 'Model pdf', 'enabled' => 1, 'position' => 1010, 'notnull' => -1, 'visible' => 0,),
107 //'url' => array('type'=>'varchar(255)', 'label'=>'URL', 'enabled'=>'1', 'position'=>55, 'notnull'=>0, 'visible'=>-1, 'csslist'=>'tdoverflow200', 'help'=>'UrlForInfoPage'),
108 'fk_c_ticket_category' => array('type' => 'integer:CTicketCategory:ticket/class/cticketcategory.class.php:0:(t.active:=:1):pos', 'label' => 'SuggestedForTicketsInGroup', 'enabled' => 'isModEnabled("ticket")', 'position' => 520, 'notnull' => 0, 'visible' => -1, 'help' => 'YouCanLinkArticleToATicketCategory', 'csslist' => 'minwidth200 tdoverflowmax250'),
109 'answer' => array('type' => 'html', 'label' => 'Solution', 'enabled' => 1, 'position' => 600, 'notnull' => 0, 'visible' => 3, 'searchall' => 1, 'csslist' => 'tdoverflowmax300', 'copytoclipboard' => 1, 'tdcss' => 'titlefieldcreate nowraponall'),
110 'status' => array('type' => 'integer', 'label' => 'Status', 'enabled' => 1, 'position' => 1000, 'notnull' => 1, 'visible' => 5, 'default' => '0', 'index' => 1, 'arrayofkeyval' => array('0' => 'Draft', '1' => 'Validated', '9' => 'Obsolete'),),
111 );
115 public $rowid;
119 public $ref;
123 public $entity;
127 public $last_main_doc;
131 public $fk_user_creat;
135 public $fk_user_modif;
139 public $fk_user_valid;
143 public $import_key;
147 public $model_pdf;
148
152 public $question;
153
157 public $answer;
161 public $url;
165 public $status;
169 public $lang;
170 // END MODULEBUILDER PROPERTIES
171
172
173 // If this object has a subtable with lines
174
175 // /**
176 // * @var string Name of subtable line
177 // */
178 // public $table_element_line = 'knowledgemanagement_knowledgerecordline';
179
180 // /**
181 // * @var string Field with ID of parent key if this object has a parent
182 // */
183 // public $fk_element = 'fk_knowledgerecord';
184
185 // /**
186 // * @var string Name of subtable class that manage subtable lines
187 // */
188 // public $class_element_line = 'KnowledgeRecordline';
189
190 // /**
191 // * @var array List of child tables. To test if we can delete object.
192 // */
193 // protected $childtables = array();
194
195 // /**
196 // * @var array List of child tables. To know object to delete on cascade.
197 // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will
198 // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object
199 // */
200 // protected $childtablesoncascade = array('knowledgemanagement_knowledgerecorddet');
201
202 // /**
203 // * @var KnowledgeRecordLine[] Array of subtable lines
204 // */
205 // public $lines = array();
206
207
208
214 public function __construct(DoliDB $db)
215 {
216 global $langs;
217
218 $this->db = $db;
219
220 $this->ismultientitymanaged = 1;
221 $this->isextrafieldmanaged = 1;
222
223 if (!getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid'])) {
224 $this->fields['rowid']['visible'] = 0;
225 }
226 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
227 $this->fields['entity']['enabled'] = 0;
228 }
229
230 // Unset fields that are disabled
231 foreach ($this->fields as $key => $val) {
232 if (isset($val['enabled']) && empty($val['enabled'])) {
233 unset($this->fields[$key]);
234 }
235 }
236
237 // Translate some data of arrayofkeyval
238 if (is_object($langs)) {
239 foreach ($this->fields as $key => $val) {
240 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
241 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
242 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
243 }
244 }
245 }
246 }
247 }
248
256 public function create(User $user, $notrigger = 0)
257 {
258 return $this->createCommon($user, $notrigger);
259 }
260
268 public function createFromClone(User $user, $fromid)
269 {
270 global $langs, $extrafields;
271 $error = 0;
272
273 dol_syslog(__METHOD__, LOG_DEBUG);
274
275 $object = new self($this->db);
276
277 $this->db->begin();
278
279 // Load source object
280 $result = $object->fetchCommon($fromid);
281 if ($result > 0 && !empty($object->table_element_line)) {
282 $object->fetchLines();
283 }
284
285 // get lines so they will be clone
286 //foreach($this->lines as $line)
287 // $line->fetch_optionals();
288
289 // Reset some properties
290 unset($object->id);
291 unset($object->fk_user_creat);
292 unset($object->import_key);
293
294 // Clear fields
295 if (property_exists($object, 'ref')) {
296 // @phan-suppress-next-line PhanTypeMismatchProperty
297 $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default'];
298 }
299 if (property_exists($object, 'question')) {
300 // @phan-suppress-next-line PhanTypeInvalidDimOffset
301 $object->question = empty($this->fields['question']['default']) ? $langs->trans("CopyOf")." ".$object->question : $this->fields['question']['default'];
302 }
303 if (property_exists($object, 'status')) {
304 $object->status = self::STATUS_DRAFT;
305 }
306 if (property_exists($object, 'date_creation')) {
307 $object->date_creation = dol_now();
308 }
309 if (property_exists($object, 'date_modification')) {
310 $object->date_modification = null;
311 }
312 // ...
313 // Clear extrafields that are unique
314 if (is_array($object->array_options) && count($object->array_options) > 0) {
315 $extrafields->fetch_name_optionals_label($this->table_element);
316 foreach ($object->array_options as $key => $option) {
317 $shortkey = preg_replace('/options_/', '', $key);
318 if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) {
319 //var_dump($key);
320 //var_dump($clonedObj->array_options[$key]); exit;
321 unset($object->array_options[$key]);
322 }
323 }
324 }
325
326 // Create clone
327 $object->context['createfromclone'] = 'createfromclone';
328 $result = $object->createCommon($user);
329 if ($result < 0) {
330 $error++;
331 $this->error = $object->error;
332 $this->errors = $object->errors;
333 }
334
335 if (!$error) {
336 // copy internal contacts
337 if ($this->copy_linked_contact($object, 'internal') < 0) {
338 $error++;
339 }
340 }
341
342 if (!$error) {
343 // copy external contacts if same company
344 if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) {
345 if ($this->copy_linked_contact($object, 'external') < 0) {
346 $error++;
347 }
348 }
349 }
350
351 unset($object->context['createfromclone']);
352
353 // End
354 if (!$error) {
355 $this->db->commit();
356 return $object;
357 } else {
358 $this->db->rollback();
359 return -1;
360 }
361 }
362
370 public function fetch($id, $ref = null)
371 {
372 $result = $this->fetchCommon($id, $ref);
373 if ($result > 0 && !empty($this->table_element_line)) {
374 $this->fetchLines();
375 }
376 return $result;
377 }
378
384 public function fetchLines()
385 {
386 $this->lines = array();
387
388 $result = $this->fetchLinesCommon();
389 return $result;
390 }
391
392
404 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
405 {
406 dol_syslog(__METHOD__, LOG_DEBUG);
407
408 $records = array();
409
410 $sql = 'SELECT ';
411 $sql .= $this->getFieldList('t');
412 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
413 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
414 $sql .= ' WHERE t.entity IN ('.getEntity($this->element).')';
415 } else {
416 $sql .= ' WHERE 1 = 1';
417 }
418
419 // Manage filter
420 if (is_array($filter)) {
421 $sqlwhere = array();
422 if (count($filter) > 0) {
423 foreach ($filter as $key => $value) {
424 if ($key == 't.rowid') {
425 $sqlwhere[] = $this->db->sanitize($key)." = ".((int) $value);
426 } elseif (array_key_exists($key, $this->fields) && in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) {
427 $sqlwhere[] = $this->db->sanitize($key)." = '".$this->db->idate($value)."'";
428 } elseif (strpos($value, '%') === false) {
429 $sqlwhere[] = $this->db->sanitize($key).' IN ('.$this->db->sanitize($this->db->escape($value)).')';
430 } else {
431 $sqlwhere[] = $this->db->sanitize($key)." LIKE '%".$this->db->escape($this->db->escapeforlike($value))."%'";
432 }
433 }
434 }
435 if (count($sqlwhere) > 0) {
436 $sql .= ' AND ('.implode(' '.$this->db->escape($filtermode).' ', $sqlwhere).')';
437 }
438
439 $filter = '';
440 }
441
442 // Manage filter
443 $errormessage = '';
444 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
445 if ($errormessage) {
446 $this->errors[] = $errormessage;
447 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
448 return -1;
449 }
450
451 if (!empty($sortfield)) {
452 $sql .= $this->db->order($sortfield, $sortorder);
453 }
454 if (!empty($limit)) {
455 $sql .= $this->db->plimit($limit, $offset);
456 }
457
458 $resql = $this->db->query($sql);
459 if ($resql) {
460 $num = $this->db->num_rows($resql);
461 $i = 0;
462 while ($i < ($limit ? min($limit, $num) : $num)) {
463 $obj = $this->db->fetch_object($resql);
464
465 $record = new self($this->db);
466 $record->setVarsFromFetchObj($obj);
467
468 $records[$record->id] = $record;
469
470 $i++;
471 }
472 $this->db->free($resql);
473
474 return $records;
475 } else {
476 $this->errors[] = 'Error '.$this->db->lasterror();
477 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
478
479 return -1;
480 }
481 }
482
490 public function update(User $user, $notrigger = 0)
491 {
492 return $this->updateCommon($user, $notrigger);
493 }
494
502 public function delete(User $user, $notrigger = 0)
503 {
504 $error = 0;
505 $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_knowledgemanagement WHERE fk_knowledgemanagement = ".((int) $this->id);
506 dol_syslog(get_class($this)."::delete", LOG_DEBUG);
507 $resql = $this->db->query($sql);
508 if (!$resql) {
509 $error++;
510 $this->error .= $this->db->lasterror();
511 $errorflag = -1;
512 }
513
514 // Delete all child tables
515 if (!$error) {
516 $elements = array('categorie_knowledgemanagement');
517 foreach ($elements as $table) {
518 if (!$error) {
519 $sql = "DELETE FROM ".MAIN_DB_PREFIX.$table;
520 $sql .= " WHERE fk_knowledgemanagement = ".(int) $this->id;
521
522 $result = $this->db->query($sql);
523 if (!$result) {
524 $error++;
525 $this->errors[] = $this->db->lasterror();
526 }
527 }
528 }
529 }
530
531 return $this->deleteCommon($user, $notrigger);
532 //return $this->deleteCommon($user, $notrigger, 1);
533 }
534
543 public function deleteLine(User $user, $idline, $notrigger = 0)
544 {
545 if ($this->status < 0) {
546 $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
547 return -2;
548 }
549
550 return $this->deleteLineCommon($user, $idline, $notrigger);
551 }
552
553
561 public function validate($user, $notrigger = 0)
562 {
563 global $conf, $langs;
564
565 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
566
567 $error = 0;
568
569 // Protection
570 if ($this->status == self::STATUS_VALIDATED) {
571 dol_syslog(get_class($this)."::validate action abandoned: already validated", LOG_WARNING);
572 return 0;
573 }
574
575 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->hasRight('knowledgemanagement', 'knowledgerecord', 'write'))
576 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->knowledgemanagement->knowledgerecord->knowledgerecord_advance->validate))))
577 {
578 $this->error='NotEnoughPermissions';
579 dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
580 return -1;
581 }*/
582
583 $now = dol_now();
584
585 $this->db->begin();
586
587 // Define new ref
588 if (!$error && (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
589 $num = $this->getNextNumRef();
590 } else {
591 $num = $this->ref;
592 }
593 $this->newref = $num;
594
595 if (!empty($num)) {
596 // Validate
597 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
598 $sql .= " SET ref = '".$this->db->escape($num)."',";
599 $sql .= " status = ".self::STATUS_VALIDATED;
600 if (!empty($this->fields['date_validation'])) {
601 $sql .= ", date_validation = '".$this->db->idate($now)."'";
602 }
603 if (!empty($this->fields['fk_user_valid'])) { // @phan-suppress-current-line PhanTypeMismatchProperty
604 $sql .= ", fk_user_valid = ".((int) $user->id);
605 }
606 $sql .= " WHERE rowid = ".((int) $this->id);
607
608 dol_syslog(get_class($this)."::validate()", LOG_DEBUG);
609 $resql = $this->db->query($sql);
610 if (!$resql) {
611 dol_print_error($this->db);
612 $this->error = $this->db->lasterror();
613 $error++;
614 }
615
616 if (!$error && !$notrigger) {
617 // Call trigger
618 $result = $this->call_trigger('KNOWLEDGERECORD_VALIDATE', $user);
619 if ($result < 0) {
620 $error++;
621 }
622 // End call triggers
623 }
624 }
625
626 if (!$error) {
627 $this->oldref = $this->ref;
628
629 // Rename directory if dir was a temporary ref
630 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
631 // Now we rename also files into index
632 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'knowledgerecord/".$this->db->escape($this->newref)."'";
633 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'knowledgerecord/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
634 $resql = $this->db->query($sql);
635 if (!$resql) {
636 $error++;
637 $this->error = $this->db->lasterror();
638 }
639 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'knowledgerecord/".$this->db->escape($this->newref)."'";
640 $sql .= " WHERE filepath = 'knowledgerecord/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
641 $resql = $this->db->query($sql);
642 if (!$resql) {
643 $error++;
644 $this->error = $this->db->lasterror();
645 }
646
647 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
648 $oldref = dol_sanitizeFileName($this->ref);
649 $newref = dol_sanitizeFileName($num);
650 $dirsource = $conf->knowledgemanagement->dir_output.'/knowledgerecord/'.$oldref;
651 $dirdest = $conf->knowledgemanagement->dir_output.'/knowledgerecord/'.$newref;
652 if (!$error && file_exists($dirsource)) {
653 dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest);
654
655 if (@rename($dirsource, $dirdest)) {
656 dol_syslog("Rename ok");
657 // Rename docs starting with $oldref with $newref
658 $listoffiles = dol_dir_list($conf->knowledgemanagement->dir_output.'/knowledgerecord/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
659 foreach ($listoffiles as $fileentry) {
660 $dirsource = $fileentry['name'];
661 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
662 $dirsource = $fileentry['path'].'/'.$dirsource;
663 $dirdest = $fileentry['path'].'/'.$dirdest;
664 @rename($dirsource, $dirdest);
665 }
666 }
667 }
668 }
669 }
670
671 // Set new ref and current status
672 if (!$error) {
673 $this->ref = $num;
674 $this->status = self::STATUS_VALIDATED;
675 }
676
677 if (!$error) {
678 $this->db->commit();
679 return 1;
680 } else {
681 $this->db->rollback();
682 return -1;
683 }
684 }
685
686
694 public function setDraft($user, $notrigger = 0)
695 {
696 // Protection
697 if ($this->status <= self::STATUS_DRAFT) {
698 return 0;
699 }
700
701 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->knowledgemanagement->write))
702 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->knowledgemanagement->knowledgemanagement_advance->validate))))
703 {
704 $this->error='Permission denied';
705 return -1;
706 }*/
707
708 return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'KNOWLEDGERECORD_UNVALIDATE');
709 }
710
718 public function cancel($user, $notrigger = 0)
719 {
720 // Protection
721 if ($this->status != self::STATUS_VALIDATED) {
722 return 0;
723 }
724
725 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->knowledgemanagement->write))
726 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->knowledgemanagement->knowledgemanagement_advance->validate))))
727 {
728 $this->error='Permission denied';
729 return -1;
730 }*/
731
732 return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'KNOWLEDGERECORD_CANCEL');
733 }
734
742 public function reopen($user, $notrigger = 0)
743 {
744 // Protection
745 if ($this->status != self::STATUS_CANCELED) {
746 return 0;
747 }
748
749 /*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->knowledgemanagement->write))
750 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->knowledgemanagement->knowledgemanagement_advance->validate))))
751 {
752 $this->error='Permission denied';
753 return -1;
754 }*/
755
756 return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'KNOWLEDGERECORD_REOPEN');
757 }
758
765 public function getTooltipContentArray($params)
766 {
767 global $conf, $langs;
768
769 $langs->loadLangs(['knowledgemanagement', 'languages']);
770
771 $datas = array();
772 $nofetch = !empty($params['nofetch']);
773
774 $datas['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("KnowledgeRecord").'</u>';
775 if (isset($this->statut)) {
776 $datas['picto'] .= ' '.$this->getLibStatut(5);
777 }
778 $datas['label'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
779 $datas['question'] = '<br><b>'.$langs->trans('Question').':</b> '.$this->question;
780 $labellang = ($this->lang ? $langs->trans('Language_'.$this->lang) : '');
781 $datas['lang'] = '<br><b>'.$langs->trans('Language').':</b> ' . picto_from_langcode($this->lang, 'class="paddingrightonly saturatemedium opacitylow"') . $labellang;
782 // show categories for this record only in ajax to not overload lists
783 if (isModEnabled('category') && !$nofetch) {
784 require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
785 $form = new Form($this->db);
786 $datas['categories'] = '<br>' . $form->showCategories($this->id, Categorie::TYPE_KNOWLEDGEMANAGEMENT, 1);
787 }
788
789 return $datas;
790 }
791
802 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
803 {
804 global $conf, $langs, $hookmanager;
805
806 if (!empty($conf->dol_no_mouse_hover)) {
807 $notooltip = 1; // Force disable tooltips
808 }
809
810 $result = '';
811
812 $params = [
813 'id' => $this->id,
814 'objecttype' => $this->element.($this->module ? '@'.$this->module : ''),
815 'option' => $option,
816 'nofetch' => 1,
817 ];
818 $classfortooltip = 'classfortooltip';
819 $dataparams = '';
820 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
821 $classfortooltip = 'classforajaxtooltip';
822 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
823 $label = '';
824 } else {
825 $label = implode($this->getTooltipContentArray($params));
826 }
827
828 $url = dol_buildpath('/knowledgemanagement/knowledgerecord_card.php', 1).'?id='.$this->id;
829
830 if ($option != 'nolink') {
831 // Add param to save lastsearch_values or not
832 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
833 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
834 $add_save_lastsearch_values = 1;
835 }
836 if ($add_save_lastsearch_values) {
837 $url .= '&save_lastsearch_values=1';
838 }
839 }
840
841 $linkclose = '';
842 if (empty($notooltip)) {
843 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
844 $label = $langs->trans("ShowKnowledgeRecord");
845 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
846 }
847 $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
848 $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
849 } else {
850 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
851 }
852
853 if ($option == 'nolink') {
854 $linkstart = '<span';
855 } else {
856 $linkstart = '<a href="'.$url.'"';
857 }
858 $linkstart .= $linkclose.'>';
859 if ($option == 'nolink') {
860 $linkend = '</span>';
861 } else {
862 $linkend = '</a>';
863 }
864
865 $result .= $linkstart;
866
867 if (empty($this->showphoto_on_popup)) {
868 if ($withpicto) {
869 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : $dataparams.' class="'.(($withpicto != 2) ? 'paddingright ' : '').$classfortooltip.'"'), 0, 0, $notooltip ? 0 : 1);
870 }
871 } else {
872 if ($withpicto) {
873 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
874
875 list($class, $module) = explode('@', $this->picto);
876 $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
877 $filearray = dol_dir_list($upload_dir, "files");
878 $filename = $filearray[0]['name'];
879 if (!empty($filename)) {
880 $pospoint = strpos($filearray[0]['name'], '.');
881
882 $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
883 if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) {
884 $result .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref"><img class="photo'.$module.'" alt="No photo" border="0" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$module.'&entity='.$conf->entity.'&file='.urlencode($pathtophoto).'"></div></div>';
885 } else {
886 $result .= '<div class="floatleft inline-block valignmiddle divphotoref"><img class="photouserphoto userphoto" alt="No photo" border="0" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$module.'&entity='.$conf->entity.'&file='.urlencode($pathtophoto).'"></div>';
887 }
888
889 $result .= '</div>';
890 } else {
891 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1);
892 }
893 }
894 }
895
896 if ($withpicto != 2) {
897 $result .= $this->ref;
898 }
899
900 $result .= $linkend;
901 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
902
903 global $action, $hookmanager;
904 $hookmanager->initHooks(array('knowledgerecorddao'));
905 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
906 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
907 if ($reshook > 0) {
908 $result = $hookmanager->resPrint;
909 } else {
910 $result .= $hookmanager->resPrint;
911 }
912
913 return $result;
914 }
915
922 public function getLibStatut($mode = 0)
923 {
924 return $this->LibStatut($this->status, $mode);
925 }
926
927 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
935 public function LibStatut($status, $mode = 0)
936 {
937 // phpcs:enable
938 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
939 global $langs;
940 //$langs->load("knowledgemanagement");
941 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
942 $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Validated');
943 $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Obsolete');
944 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
945 $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Validated');
946 $this->labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Obsolete');
947 }
948
949 $statusType = 'status'.$status;
950 if ($status == self::STATUS_VALIDATED) {
951 $statusType = 'status4';
952 }
953 if ($status == self::STATUS_CANCELED) {
954 $statusType = 'status6';
955 }
956
957 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
958 }
959
966 public function info($id)
967 {
968 $sql = 'SELECT rowid, date_creation as datec, tms as datem,';
969 $sql .= ' fk_user_creat, fk_user_modif';
970 $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
971 $sql .= ' WHERE t.rowid = '.((int) $id);
972 $result = $this->db->query($sql);
973 if ($result) {
974 if ($this->db->num_rows($result)) {
975 $obj = $this->db->fetch_object($result);
976
977 $this->id = $obj->rowid;
978
979 $this->user_creation_id = $obj->fk_user_creat;
980 $this->user_modification_id = $obj->fk_user_modif;
981 $this->date_creation = $this->db->jdate($obj->datec);
982 $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
983 }
984
985 $this->db->free($result);
986 } else {
987 dol_print_error($this->db);
988 }
989 }
990
997 public function initAsSpecimen()
998 {
999 $this->question = "ABCD";
1000
1001 return $this->initAsSpecimenCommon();
1002 }
1003
1009 public function getLinesArray()
1010 {
1011 $this->lines = array();
1012
1013 $objectline = new KnowledgeRecordLine($this->db);
1014 $result = $objectline->fetchAll('ASC', 'position', 0, 0, '(fk_knowledgerecord:=:'.((int) $this->id).')');
1015
1016 if (is_numeric($result)) {
1017 $this->error = $objectline->error;
1018 $this->errors = $objectline->errors;
1019 return $result;
1020 } else {
1021 $this->lines = $result;
1022 // @phpstan-ignore-next-line
1023 return $result; // @phan-suppress-current-line PhanTypeMismatchReturn
1024 }
1025 }
1026
1032 public function getNextNumRef()
1033 {
1034 global $langs, $conf;
1035 $langs->load("knowledgemanagement");
1036
1037 if (!getDolGlobalString('KNOWLEDGEMANAGEMENT_KNOWLEDGERECORD_ADDON')) {
1038 $conf->global->KNOWLEDGEMANAGEMENT_KNOWLEDGERECORD_ADDON = 'mod_knowledgerecord_standard';
1039 }
1040
1041 if (getDolGlobalString('KNOWLEDGEMANAGEMENT_KNOWLEDGERECORD_ADDON')) {
1042 $mybool = false;
1043
1044 $file = getDolGlobalString('KNOWLEDGEMANAGEMENT_KNOWLEDGERECORD_ADDON') . ".php";
1045 $classname = getDolGlobalString('KNOWLEDGEMANAGEMENT_KNOWLEDGERECORD_ADDON');
1046
1047 // Include file with class
1048 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1049 foreach ($dirmodels as $reldir) {
1050 $dir = dol_buildpath($reldir."core/modules/knowledgemanagement/");
1051
1052 // Load file with numbering class (if found)
1053 $mybool = ((bool) @include_once $dir.$file) || $mybool;
1054 }
1055
1056 if (!$mybool) {
1057 dol_print_error(null, "Failed to include file ".$file);
1058 return '';
1059 }
1060
1061 if (class_exists($classname)) {
1062 $obj = new $classname();
1063 '@phan-var-force ModeleNumRefKnowledgeRecord $obj';
1064 $numref = $obj->getNextValue($this);
1065
1066 if ($numref != '' && $numref != '-1') {
1067 return $numref;
1068 } else {
1069 $this->error = $obj->error;
1070 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1071 return "";
1072 }
1073 } else {
1074 print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1075 return "";
1076 }
1077 } else {
1078 print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1079 return "";
1080 }
1081 }
1082
1094 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1095 {
1096 global $conf, $langs;
1097
1098 $result = 0;
1099 $includedocgeneration = 0;
1100
1101 $langs->load("knowledgemanagement");
1102
1103 if (!dol_strlen($modele)) {
1104 $modele = 'standard_knowledgerecord';
1105
1106 if (!empty($this->model_pdf)) {
1107 $modele = $this->model_pdf;
1108 } elseif (getDolGlobalString('KNOWLEDGERECORD_ADDON_PDF')) {
1109 $modele = getDolGlobalString('KNOWLEDGERECORD_ADDON_PDF');
1110 }
1111 }
1112
1113 $modelpath = "core/modules/knowledgemanagement/doc/";
1114
1115 if ($includedocgeneration && !empty($modele)) {
1116 $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1117 }
1118
1119 return $result;
1120 }
1121
1129 public function doScheduledJob()
1130 {
1131 global $conf, $langs;
1132
1133 //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log';
1134
1135 $error = 0;
1136 $this->output = '';
1137 $this->error = '';
1138
1139 dol_syslog(__METHOD__, LOG_DEBUG);
1140
1141 $now = dol_now();
1142
1143 $this->db->begin();
1144
1145 // ...
1146
1147 $this->db->commit();
1148
1149 return $error;
1150 }
1151
1162 public function setCategories($categories)
1163 {
1164 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1165 return parent::setCategoriesCommon($categories, Categorie::TYPE_KNOWLEDGEMANAGEMENT);
1166 }
1167
1175 public function getKanbanView($option = '', $arraydata = null)
1176 {
1177 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
1178
1179 $return = '<div class="box-flex-item box-flex-grow-zero">';
1180 $return .= '<div class="info-box info-box-sm">';
1181 $return .= '<span class="info-box-icon bg-infobox-action">';
1182 $return .= img_picto('', $this->picto);
1183 $return .= '</span>';
1184 $return .= '<div class="info-box-content">';
1185 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
1186 if ($selected >= 0) {
1187 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
1188 }
1189 if (property_exists($this, 'lang') && !empty($this->lang)) {
1190 //$return .= '<br><span class="opacitymedium">'.$langs->trans("Language").'</span> : <span class="info-box-label" title="'.$langs->trans("Language_".$this->lang).'">'.$langs->trans("Language_".$this->lang, '', '', '', '', 12).'</span>';
1191 $return .= '<br>'.picto_from_langcode($this->lang, 'class="paddingrightonly saturatemedium opacitylow paddingrightonly"');
1192 }
1193 if (property_exists($this, 'question')) {
1194 $return .= '<div class="info-box-label tdoverflowmax150 classfortooltip" title="'.dolPrintHTMLForAttribute($this->question).'">'.dolGetFirstLineOfText($this->question).'</div>';
1195 }
1196 if (method_exists($this, 'getLibStatut')) {
1197 $return .= '<div class="info-box-status">'.$this->getLibStatut(3).'</div>';
1198 }
1199 $return .= '</div>';
1200 $return .= '</div>';
1201 $return .= '</div>';
1202 return $return;
1203 }
1204}
1205
1206
1207require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
1208
1213{
1214 // To complete with content of an object KnowledgeRecordLine
1215 // We should have a field rowid, fk_knowledgerecord and position
1216
1222 public function __construct(DoliDB $db)
1223 {
1224 $this->db = $db;
1225
1226 $this->isextrafieldmanaged = 0;
1227 }
1228}
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
$object ref
Definition info.php:79
Parent class of all other business classes (invoices, contracts, proposals, orders,...
deleteLineCommon(User $user, $idline, $notrigger=0)
Delete a line of object in database.
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
createCommon(User $user, $notrigger=0)
Create object in the database.
getFieldList($alias='', $excludefields=array())
Function to concat keys of fields.
updateCommon(User $user, $notrigger=0)
Update object into database.
setStatusCommon($user, $status, $notrigger=0, $triggercode='')
Set to a status.
initAsSpecimenCommon()
Initialise object with example values Id must be 0 if object instance is a specimen.
copy_linked_contact($objFrom, $source='internal')
Copy contact from one element to current.
fetchLinesCommon($morewhere='', $noextrafields=0)
Load object in memory from the database.
fetchCommon($id, $ref=null, $morewhere='', $noextrafields=0)
Load object in memory from the database.
deleteCommon(User $user, $notrigger=0, $forcechilddeletion=0)
Delete object in database.
call_trigger($triggerName, $user)
Call trigger based on this instance.
Parent class for class inheritance lines of business objects This class is useless for the moment so ...
Class to manage Dolibarr database access.
Class to manage generation of HTML components Only common components must be here.
Class for KnowledgeRecord.
getKanbanView($option='', $arraydata=null)
Return clickable link of object (with eventually picto)
fetch($id, $ref=null)
Load object in memory from the database.
validate($user, $notrigger=0)
Validate object.
getNextNumRef()
Returns the reference to the following non used object depending on the active numbering module.
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, $filter='', $filtermode='AND')
Load list of objects in memory from the database.
info($id)
Load the info information in the object.
cancel($user, $notrigger=0)
Set cancel status.
update(User $user, $notrigger=0)
Update object into database.
fetchLines()
Load object lines in memory from the database.
LibStatut($status, $mode=0)
Return the status.
create(User $user, $notrigger=0)
Create object into database.
getTooltipContentArray($params)
getTooltipContentArray
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionally the picto)
createFromClone(User $user, $fromid)
Clone an object into another one.
deleteLine(User $user, $idline, $notrigger=0)
Delete a line of object in database.
doScheduledJob()
Action executed by scheduler CAN BE A CRON TASK.
setCategories($categories)
Sets object to supplied categories.
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
getLinesArray()
Create an array of lines.
__construct(DoliDB $db)
Constructor.
getLibStatut($mode=0)
Return the label of the status.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
reopen($user, $notrigger=0)
Set back to validated status.
setDraft($user, $notrigger=0)
Set draft status.
Class KnowledgeRecordLine.
__construct(DoliDB $db)
Constructor.
Class to manage Dolibarr users.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:162
dol_dir_list($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:63
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.