dolibarr 19.0.3
myobject.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2023 Frédéric France <frederic.france@netlogic.fr>
4 * Copyright (C) ---Put here your own copyright and developer email---
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 = 'mymodule';
40
44 public $element = 'myobject';
45
49 public $table_element = 'mymodule_myobject';
50
55 public $ismultientitymanaged = 0;
56
60 public $isextrafieldmanaged = 1;
61
65 public $picto = 'fa-file';
66
67
68 const STATUS_DRAFT = 0;
69 const STATUS_VALIDATED = 1;
70 const STATUS_CANCELED = 9;
71
111 // BEGIN MODULEBUILDER PROPERTIES
115 public $fields = array(
116 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'noteditable'=>1, 'notnull'=> 1, 'index'=>1, 'position'=>1, 'comment'=>'Id', 'css'=>'left'),
117 'entity' => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'notnull'=> 1, 'default'=>1, 'index'=>1, 'position'=>10),
118 'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>1, 'noteditable'=>0, 'default'=>'', 'notnull'=> 1, 'showoncombobox'=>1, 'index'=>1, 'position'=>20, 'searchall'=>1, 'comment'=>'Reference of object', 'validate'=>1),
119 'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>1, 'visible'=>1, 'position'=>30, 'searchall'=>1, 'css'=>'minwidth300', 'cssview'=>'wordbreak', 'help'=>'Help text', 'showoncombobox'=>2, 'validate'=>1, 'alwayseditable'=>1),
120 'amount' => array('type'=>'price', 'label'=>'Amount', 'enabled'=>1, 'visible'=>1, 'default'=>'null', 'position'=>40, 'searchall'=>0, 'isameasure'=>1, 'help'=>'Help text for amount', 'validate'=>1),
121 'qty' => array('type'=>'real', 'label'=>'Qty', 'enabled'=>1, 'visible'=>1, 'default'=>'0', 'position'=>45, 'searchall'=>0, 'isameasure'=>1, 'help'=>'Help text for quantity', 'css'=>'maxwidth75imp', 'validate'=>1),
122 'fk_soc' => array('type'=>'integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))', 'picto'=>'company', 'label'=>'ThirdParty', 'visible'=> 1, 'enabled'=>'isModEnabled("societe")', 'position'=>50, 'notnull'=>-1, 'index'=>1, 'help'=>'OrganizationEventLinkToThirdParty', 'validate'=>1, 'css'=>'maxwidth500 widthcentpercentminusxx', 'csslist'=>'tdoverflowmax150'),
123 'fk_project' => array('type'=>'integer:Project:projet/class/project.class.php:1', 'label'=>'Project', 'picto'=>'project', 'enabled'=>'isModEnabled("project")', 'visible'=>-1, 'position'=>52, 'notnull'=>-1, 'index'=>1, 'validate'=>1, 'css'=>'maxwidth500 widthcentpercentminusxx', 'csslist'=>'tdoverflowmax150'),
124 'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>3, 'position'=>60, 'validate'=>1),
125 'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>61, 'validate'=>1, 'cssview'=>'wordbreak'),
126 'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>62, 'validate'=>1, 'cssview'=>'wordbreak'),
127 'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'notnull'=> 1, 'position'=>500),
128 'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'notnull'=> 0, 'position'=>501),
129 //'date_validation ' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>502),
130 'fk_user_creat' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'picto'=>'user', 'enabled'=>1, 'visible'=>-2, 'notnull'=> 1, 'position'=>510, 'foreignkey'=>'user.rowid', 'csslist'=>'tdoverflowmax150'),
131 'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'picto'=>'user', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>511, 'csslist'=>'tdoverflowmax150'),
132 //'fk_user_valid' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>512),
133 'last_main_doc' => array('type'=>'varchar(255)', 'label'=>'LastMainDoc', 'enabled'=>1, 'visible'=>0, 'notnull'=>0, 'position'=>600),
134 'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'index'=>0, 'position'=>1000),
135 'model_pdf' => array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'notnull'=>-1, 'position'=>1010),
136 'status' => array('type'=>'integer', 'label'=>'Status', 'enabled'=>1, 'visible'=>1, 'notnull'=> 1, 'default'=>0, 'index'=>1, 'position'=>2000, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Validated', 9=>'Canceled'), 'validate'=>1),
137 );
138
142 public $rowid;
143
147 public $ref;
148
152 public $entity;
153
157 public $label;
158
162 public $amount;
163
167 public $socid; // both socid and fk_soc are used
168 public $fk_soc; // both socid and fk_soc are used
169
173 public $status;
174
178 public $date_creation;
179
183 public $tms;
184
188 public $fk_user_creat;
189
193 public $fk_user_modif;
194
198 public $last_main_doc;
199
203 public $import_key;
204 // END MODULEBUILDER PROPERTIES
205
206
207 // If this object has a subtable with lines
208
209 // /**
210 // * @var string Name of subtable line
211 // */
212 // public $table_element_line = 'mymodule_myobjectline';
213
214 // /**
215 // * @var string Field with ID of parent key if this object has a parent
216 // */
217 // public $fk_element = 'fk_myobject';
218
219 // /**
220 // * @var string Name of subtable class that manage subtable lines
221 // */
222 // public $class_element_line = 'MyObjectline';
223
224 // /**
225 // * @var array List of child tables. To test if we can delete object.
226 // */
227 // protected $childtables = array('mychildtable' => array('name'=>'MyObject', 'fk_element'=>'fk_myobject'));
228
229 // /**
230 // * @var array List of child tables. To know object to delete on cascade.
231 // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will
232 // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object
233 // */
234 // protected $childtablesoncascade = array('mymodule_myobjectdet');
235
236 // /**
237 // * @var MyObjectLine[] Array of subtable lines
238 // */
239 // public $lines = array();
240
241
242
248 public function __construct(DoliDB $db)
249 {
250 global $conf, $langs;
251
252 $this->db = $db;
253
254 if (!getDolGlobalInt('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid']) && !empty($this->fields['ref'])) {
255 $this->fields['rowid']['visible'] = 0;
256 }
257 if (!isModEnabled('multicompany') && isset($this->fields['entity'])) {
258 $this->fields['entity']['enabled'] = 0;
259 }
260
261 // Example to show how to set values of fields definition dynamically
262 /*if ($user->hasRight('mymodule', 'myobject', 'read')) {
263 $this->fields['myfield']['visible'] = 1;
264 $this->fields['myfield']['noteditable'] = 0;
265 }*/
266
267 // Unset fields that are disabled
268 foreach ($this->fields as $key => $val) {
269 if (isset($val['enabled']) && empty($val['enabled'])) {
270 unset($this->fields[$key]);
271 }
272 }
273
274 // Translate some data of arrayofkeyval
275 if (is_object($langs)) {
276 foreach ($this->fields as $key => $val) {
277 if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
278 foreach ($val['arrayofkeyval'] as $key2 => $val2) {
279 $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
280 }
281 }
282 }
283 }
284 }
285
293 public function create(User $user, $notrigger = false)
294 {
295 $resultcreate = $this->createCommon($user, $notrigger);
296
297 //$resultvalidate = $this->validate($user, $notrigger);
298
299 return $resultcreate;
300 }
301
309 public function createFromClone(User $user, $fromid)
310 {
311 global $langs, $extrafields;
312 $error = 0;
313
314 dol_syslog(__METHOD__, LOG_DEBUG);
315
316 $object = new self($this->db);
317
318 $this->db->begin();
319
320 // Load source object
321 $result = $object->fetchCommon($fromid);
322 if ($result > 0 && !empty($object->table_element_line)) {
323 $object->fetchLines();
324 }
325
326 // get lines so they will be clone
327 //foreach($this->lines as $line)
328 // $line->fetch_optionals();
329
330 // Reset some properties
331 unset($object->id);
332 unset($object->fk_user_creat);
333 unset($object->import_key);
334
335 // Clear fields
336 if (property_exists($object, 'ref')) {
337 $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default'];
338 }
339 if (property_exists($object, 'label')) {
340 $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
341 }
342 if (property_exists($object, 'status')) {
343 $object->status = self::STATUS_DRAFT;
344 }
345 if (property_exists($object, 'date_creation')) {
346 $object->date_creation = dol_now();
347 }
348 if (property_exists($object, 'date_modification')) {
349 $object->date_modification = null;
350 }
351 // ...
352 // Clear extrafields that are unique
353 if (is_array($object->array_options) && count($object->array_options) > 0) {
354 $extrafields->fetch_name_optionals_label($this->table_element);
355 foreach ($object->array_options as $key => $option) {
356 $shortkey = preg_replace('/options_/', '', $key);
357 if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) {
358 //var_dump($key);
359 //var_dump($clonedObj->array_options[$key]); exit;
360 unset($object->array_options[$key]);
361 }
362 }
363 }
364
365 // Create clone
366 $object->context['createfromclone'] = 'createfromclone';
367 $result = $object->createCommon($user);
368 if ($result < 0) {
369 $error++;
370 $this->setErrorsFromObject($object);
371 }
372
373 if (!$error) {
374 // copy internal contacts
375 if ($this->copy_linked_contact($object, 'internal') < 0) {
376 $error++;
377 }
378 }
379
380 if (!$error) {
381 // copy external contacts if same company
382 if (!empty($object->socid) && property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) {
383 if ($this->copy_linked_contact($object, 'external') < 0) {
384 $error++;
385 }
386 }
387 }
388
389 unset($object->context['createfromclone']);
390
391 // End
392 if (!$error) {
393 $this->db->commit();
394 return $object;
395 } else {
396 $this->db->rollback();
397 return -1;
398 }
399 }
400
410 public function fetch($id, $ref = null, $noextrafields = 0, $nolines = 0)
411 {
412 $result = $this->fetchCommon($id, $ref, '', $noextrafields);
413 if ($result > 0 && !empty($this->table_element_line) && empty($nolines)) {
414 $this->fetchLines($noextrafields);
415 }
416 return $result;
417 }
418
425 public function fetchLines($noextrafields = 0)
426 {
427 $this->lines = array();
428
429 $result = $this->fetchLinesCommon('', $noextrafields);
430 return $result;
431 }
432
433
445 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
446 {
447 dol_syslog(__METHOD__, LOG_DEBUG);
448
449 $records = array();
450
451 $sql = "SELECT ";
452 $sql .= $this->getFieldList('t');
453 $sql .= " FROM ".$this->db->prefix().$this->table_element." as t";
454 if (isset($this->isextrafieldmanaged) && $this->isextrafieldmanaged == 1) {
455 $sql .= " LEFT JOIN ".$this->db->prefix().$this->table_element."_extrafields as te ON te.fk_object = t.rowid";
456 }
457 if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
458 $sql .= " WHERE t.entity IN (".getEntity($this->element).")";
459 } else {
460 $sql .= " WHERE 1 = 1";
461 }
462 // Manage filter
463 $sqlwhere = array();
464 if (count($filter) > 0) {
465 foreach ($filter as $key => $value) {
466 $columnName = preg_replace('/^t\./', '', $key);
467 if ($key === 'customsql') {
468 // Never use 'customsql' with a value from user input since it is injected as is. The value must be hard coded.
469 $sqlwhere[] = $value;
470 continue;
471 } elseif (isset($this->fields[$columnName])) {
472 $type = $this->fields[$columnName]['type'];
473 if (preg_match('/^integer/', $type)) {
474 if (is_int($value)) {
475 // single value
476 $sqlwhere[] = $key . " = " . intval($value);
477 } elseif (is_array($value)) {
478 if (empty($value)) {
479 continue;
480 }
481 $sqlwhere[] = $key . ' IN (' . $this->db->sanitize(implode(',', array_map('intval', $value))) . ')';
482 }
483 continue;
484 } elseif (in_array($type, array('date', 'datetime', 'timestamp'))) {
485 $sqlwhere[] = $key . " = '" . $this->db->idate($value) . "'";
486 continue;
487 }
488 }
489
490 // when the $key doesn't fall into the previously handled categories, we do as if the column were a varchar/text
491 if (is_array($value) && count($value)) {
492 $value = implode(',', array_map(function ($v) {
493 return "'" . $this->db->sanitize($this->db->escape($v)) . "'";
494 }, $value));
495 $sqlwhere[] = $key . ' IN (' . $this->db->sanitize($value, true) . ')';
496 } elseif (is_scalar($value)) {
497 if (strpos($value, '%') === false) {
498 $sqlwhere[] = $key . " = '" . $this->db->sanitize($this->db->escape($value)) . "'";
499 } else {
500 $sqlwhere[] = $key . " LIKE '%" . $this->db->escape($this->db->escapeforlike($value)) . "%'";
501 }
502 }
503 }
504 }
505 if (count($sqlwhere) > 0) {
506 $sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")";
507 }
508
509 if (!empty($sortfield)) {
510 $sql .= $this->db->order($sortfield, $sortorder);
511 }
512 if (!empty($limit)) {
513 $sql .= $this->db->plimit($limit, $offset);
514 }
515
516 $resql = $this->db->query($sql);
517 if ($resql) {
518 $num = $this->db->num_rows($resql);
519 $i = 0;
520 while ($i < ($limit ? min($limit, $num) : $num)) {
521 $obj = $this->db->fetch_object($resql);
522
523 $record = new self($this->db);
524 $record->setVarsFromFetchObj($obj);
525
526 $records[$record->id] = $record;
527
528 $i++;
529 }
530 $this->db->free($resql);
531
532 return $records;
533 } else {
534 $this->errors[] = 'Error '.$this->db->lasterror();
535 dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
536
537 return -1;
538 }
539 }
540
548 public function update(User $user, $notrigger = false)
549 {
550 return $this->updateCommon($user, $notrigger);
551 }
552
560 public function delete(User $user, $notrigger = false)
561 {
562 return $this->deleteCommon($user, $notrigger);
563 //return $this->deleteCommon($user, $notrigger, 1);
564 }
565
574 public function deleteLine(User $user, $idline, $notrigger = false)
575 {
576 if ($this->status < 0) {
577 $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
578 return -2;
579 }
580
581 return $this->deleteLineCommon($user, $idline, $notrigger);
582 }
583
584
592 public function validate($user, $notrigger = 0)
593 {
594 global $conf, $langs;
595
596 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
597
598 $error = 0;
599
600 // Protection
601 if ($this->status == self::STATUS_VALIDATED) {
602 dol_syslog(get_class($this)."::validate action abandonned: already validated", LOG_WARNING);
603 return 0;
604 }
605
606 /* if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule', 'myobject', 'write'))
607 || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule', 'myobject_advance', 'validate')))
608 {
609 $this->error='NotEnoughPermissions';
610 dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
611 return -1;
612 }*/
613
614 $now = dol_now();
615
616 $this->db->begin();
617
618 // Define new ref
619 if (!$error && (preg_match('/^[\‍(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
620 $num = $this->getNextNumRef();
621 } else {
622 $num = $this->ref;
623 }
624 $this->newref = $num;
625
626 if (!empty($num)) {
627 // Validate
628 $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
629 $sql .= " SET ref = '".$this->db->escape($num)."',";
630 $sql .= " status = ".self::STATUS_VALIDATED;
631 if (!empty($this->fields['date_validation'])) {
632 $sql .= ", date_validation = '".$this->db->idate($now)."'";
633 }
634 if (!empty($this->fields['fk_user_valid'])) {
635 $sql .= ", fk_user_valid = ".((int) $user->id);
636 }
637 $sql .= " WHERE rowid = ".((int) $this->id);
638
639 dol_syslog(get_class($this)."::validate()", LOG_DEBUG);
640 $resql = $this->db->query($sql);
641 if (!$resql) {
642 dol_print_error($this->db);
643 $this->error = $this->db->lasterror();
644 $error++;
645 }
646
647 if (!$error && !$notrigger) {
648 // Call trigger
649 $result = $this->call_trigger('MYOBJECT_VALIDATE', $user);
650 if ($result < 0) {
651 $error++;
652 }
653 // End call triggers
654 }
655 }
656
657 if (!$error) {
658 $this->oldref = $this->ref;
659
660 // Rename directory if dir was a temporary ref
661 if (preg_match('/^[\‍(]?PROV/i', $this->ref)) {
662 // Now we rename also files into index
663 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'myobject/".$this->db->escape($this->newref)."'";
664 $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'myobject/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
665 $resql = $this->db->query($sql);
666 if (!$resql) {
667 $error++;
668 $this->error = $this->db->lasterror();
669 }
670 $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'myobject/".$this->db->escape($this->newref)."'";
671 $sql .= " WHERE filepath = 'myobject/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
672 $resql = $this->db->query($sql);
673 if (!$resql) {
674 $error++;
675 $this->error = $this->db->lasterror();
676 }
677
678 // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
679 $oldref = dol_sanitizeFileName($this->ref);
680 $newref = dol_sanitizeFileName($num);
681 $dirsource = $conf->mymodule->dir_output.'/myobject/'.$oldref;
682 $dirdest = $conf->mymodule->dir_output.'/myobject/'.$newref;
683 if (!$error && file_exists($dirsource)) {
684 dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest);
685
686 if (@rename($dirsource, $dirdest)) {
687 dol_syslog("Rename ok");
688 // Rename docs starting with $oldref with $newref
689 $listoffiles = dol_dir_list($conf->mymodule->dir_output.'/myobject/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
690 foreach ($listoffiles as $fileentry) {
691 $dirsource = $fileentry['name'];
692 $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
693 $dirsource = $fileentry['path'].'/'.$dirsource;
694 $dirdest = $fileentry['path'].'/'.$dirdest;
695 @rename($dirsource, $dirdest);
696 }
697 }
698 }
699 }
700 }
701
702 // Set new ref and current status
703 if (!$error) {
704 $this->ref = $num;
705 $this->status = self::STATUS_VALIDATED;
706 }
707
708 if (!$error) {
709 $this->db->commit();
710 return 1;
711 } else {
712 $this->db->rollback();
713 return -1;
714 }
715 }
716
717
725 public function setDraft($user, $notrigger = 0)
726 {
727 // Protection
728 if ($this->status <= self::STATUS_DRAFT) {
729 return 0;
730 }
731
732 /* if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule','write'))
733 || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule','mymodule_advance','validate'))))
734 {
735 $this->error='Permission denied';
736 return -1;
737 }*/
738
739 return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'MYMODULE_MYOBJECT_UNVALIDATE');
740 }
741
749 public function cancel($user, $notrigger = 0)
750 {
751 // Protection
752 if ($this->status != self::STATUS_VALIDATED) {
753 return 0;
754 }
755
756 /* if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule','write'))
757 || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule','mymodule_advance','validate'))))
758 {
759 $this->error='Permission denied';
760 return -1;
761 }*/
762
763 return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'MYMODULE_MYOBJECT_CANCEL');
764 }
765
773 public function reopen($user, $notrigger = 0)
774 {
775 // Protection
776 if ($this->status == self::STATUS_VALIDATED) {
777 return 0;
778 }
779
780 /*if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule','write'))
781 || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('mymodule','mymodule_advance','validate'))))
782 {
783 $this->error='Permission denied';
784 return -1;
785 }*/
786
787 return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'MYMODULE_MYOBJECT_REOPEN');
788 }
789
797 public function getTooltipContentArray($params)
798 {
799 global $langs;
800
801 $datas = [];
802
803 if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER')) {
804 return ['optimize' => $langs->trans("ShowMyObject")];
805 }
806 $datas['picto'] = img_picto('', $this->picto).' <u>'.$langs->trans("MyObject").'</u>';
807 if (isset($this->status)) {
808 $datas['picto'] .= ' '.$this->getLibStatut(5);
809 }
810 if (property_exists($this, 'ref')) {
811 $datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
812 }
813 if (property_exists($this, 'label')) {
814 $datas['ref'] = '<br>'.$langs->trans('Label').':</b> '.$this->label;
815 }
816
817 return $datas;
818 }
819
830 public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
831 {
832 global $conf, $langs, $hookmanager;
833
834 if (!empty($conf->dol_no_mouse_hover)) {
835 $notooltip = 1; // Force disable tooltips
836 }
837
838 $result = '';
839 $params = [
840 'id' => $this->id,
841 'objecttype' => $this->element.($this->module ? '@'.$this->module : ''),
842 'option' => $option,
843 ];
844 $classfortooltip = 'classfortooltip';
845 $dataparams = '';
846 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
847 $classfortooltip = 'classforajaxtooltip';
848 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
849 $label = '';
850 } else {
851 $label = implode($this->getTooltipContentArray($params));
852 }
853
854 $url = dol_buildpath('/mymodule/myobject_card.php', 1).'?id='.$this->id;
855
856 if ($option !== 'nolink') {
857 // Add param to save lastsearch_values or not
858 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
859 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
860 $add_save_lastsearch_values = 1;
861 }
862 if ($url && $add_save_lastsearch_values) {
863 $url .= '&save_lastsearch_values=1';
864 }
865 }
866
867 $linkclose = '';
868 if (empty($notooltip)) {
869 if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER')) {
870 $label = $langs->trans("ShowMyObject");
871 $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
872 }
873 $linkclose .= ($label ? ' title="'.dol_escape_htmltag($label, 1).'"' : ' title="tocomplete"');
874 $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
875 } else {
876 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
877 }
878
879 if ($option == 'nolink' || empty($url)) {
880 $linkstart = '<span';
881 } else {
882 $linkstart = '<a href="'.$url.'"';
883 }
884 $linkstart .= $linkclose.'>';
885 if ($option == 'nolink' || empty($url)) {
886 $linkend = '</span>';
887 } else {
888 $linkend = '</a>';
889 }
890
891 $result .= $linkstart;
892
893 if (empty($this->showphoto_on_popup)) {
894 if ($withpicto) {
895 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1);
896 }
897 } else {
898 if ($withpicto) {
899 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
900
901 list($class, $module) = explode('@', $this->picto);
902 $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
903 $filearray = dol_dir_list($upload_dir, "files");
904 $filename = $filearray[0]['name'];
905 if (!empty($filename)) {
906 $pospoint = strpos($filearray[0]['name'], '.');
907
908 $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
909 if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) {
910 $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>';
911 } else {
912 $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>';
913 }
914
915 $result .= '</div>';
916 } else {
917 $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'"'), 0, 0, $notooltip ? 0 : 1);
918 }
919 }
920 }
921
922 if ($withpicto != 2) {
923 $result .= $this->ref;
924 }
925
926 $result .= $linkend;
927 //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
928
929 global $action, $hookmanager;
930 $hookmanager->initHooks(array($this->element.'dao'));
931 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
932 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
933 if ($reshook > 0) {
934 $result = $hookmanager->resPrint;
935 } else {
936 $result .= $hookmanager->resPrint;
937 }
938
939 return $result;
940 }
941
949 public function getKanbanView($option = '', $arraydata = null)
950 {
951 global $conf, $langs;
952
953 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
954
955 $return = '<div class="box-flex-item box-flex-grow-zero">';
956 $return .= '<div class="info-box info-box-sm">';
957 $return .= '<span class="info-box-icon bg-infobox-action">';
958 $return .= img_picto('', $this->picto);
959 $return .= '</span>';
960 $return .= '<div class="info-box-content">';
961 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref).'</span>';
962 if ($selected >= 0) {
963 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
964 }
965 if (property_exists($this, 'label')) {
966 $return .= ' <div class="inline-block opacitymedium valignmiddle tdoverflowmax100">'.$this->label.'</div>';
967 }
968 if (property_exists($this, 'thirdparty') && is_object($this->thirdparty)) {
969 $return .= '<br><div class="info-box-ref tdoverflowmax150">'.$this->thirdparty->getNomUrl(1).'</div>';
970 }
971 if (property_exists($this, 'amount')) {
972 $return .= '<br>';
973 $return .= '<span class="info-box-label amount">'.price($this->amount, 0, $langs, 1, -1, -1, $conf->currency).'</span>';
974 }
975 if (method_exists($this, 'getLibStatut')) {
976 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
977 }
978 $return .= '</div>';
979 $return .= '</div>';
980 $return .= '</div>';
981
982 return $return;
983 }
984
991 public function getLabelStatus($mode = 0)
992 {
993 return $this->LibStatut($this->status, $mode);
994 }
995
1002 public function getLibStatut($mode = 0)
1003 {
1004 return $this->LibStatut($this->status, $mode);
1005 }
1006
1007 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1015 public function LibStatut($status, $mode = 0)
1016 {
1017 // phpcs:enable
1018 if (is_null($status)) {
1019 return '';
1020 }
1021
1022 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
1023 global $langs;
1024 //$langs->load("mymodule@mymodule");
1025 $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1026 $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled');
1027 $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled');
1028 $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft');
1029 $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled');
1030 $this->labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled');
1031 }
1032
1033 $statusType = 'status'.$status;
1034 //if ($status == self::STATUS_VALIDATED) $statusType = 'status1';
1035 if ($status == self::STATUS_CANCELED) {
1036 $statusType = 'status6';
1037 }
1038
1039 return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
1040 }
1041
1048 public function info($id)
1049 {
1050 $sql = "SELECT rowid,";
1051 $sql .= " date_creation as datec, tms as datem";
1052 if (!empty($this->fields['date_validation'])) {
1053 $sql .= ", date_validation as datev";
1054 }
1055 if (!empty($this->fields['fk_user_creat'])) {
1056 $sql .= ", fk_user_creat";
1057 }
1058 if (!empty($this->fields['fk_user_modif'])) {
1059 $sql .= ", fk_user_modif";
1060 }
1061 if (!empty($this->fields['fk_user_valid'])) {
1062 $sql .= ", fk_user_valid";
1063 }
1064 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
1065 $sql .= " WHERE t.rowid = ".((int) $id);
1066
1067 $result = $this->db->query($sql);
1068 if ($result) {
1069 if ($this->db->num_rows($result)) {
1070 $obj = $this->db->fetch_object($result);
1071
1072 $this->id = $obj->rowid;
1073
1074 if (!empty($this->fields['fk_user_creat'])) {
1075 $this->user_creation_id = $obj->fk_user_creat;
1076 }
1077 if (!empty($this->fields['fk_user_modif'])) {
1078 $this->user_modification_id = $obj->fk_user_modif;
1079 }
1080 if (!empty($this->fields['fk_user_valid'])) {
1081 $this->user_validation_id = $obj->fk_user_valid;
1082 }
1083 $this->date_creation = $this->db->jdate($obj->datec);
1084 $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
1085 if (!empty($obj->datev)) {
1086 $this->date_validation = empty($obj->datev) ? '' : $this->db->jdate($obj->datev);
1087 }
1088 }
1089
1090 $this->db->free($result);
1091 } else {
1092 dol_print_error($this->db);
1093 }
1094 }
1095
1102 public function initAsSpecimen()
1103 {
1104 // Set here init that are not commonf fields
1105 // $this->property1 = ...
1106 // $this->property2 = ...
1107
1108 $this->initAsSpecimenCommon();
1109 }
1110
1116 public function getLinesArray()
1117 {
1118 $this->lines = array();
1119
1120 $objectline = new MyObjectLine($this->db);
1121 $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_myobject = '.((int) $this->id)));
1122
1123 if (is_numeric($result)) {
1124 $this->setErrorsFromObject($objectline);
1125 return $result;
1126 } else {
1127 $this->lines = $result;
1128 return $this->lines;
1129 }
1130 }
1131
1137 public function getNextNumRef()
1138 {
1139 global $langs, $conf;
1140 $langs->load("mymodule@mymodule");
1141
1142 if (!getDolGlobalString('MYMODULE_MYOBJECT_ADDON')) {
1143 $conf->global->MYMODULE_MYOBJECT_ADDON = 'mod_myobject_standard';
1144 }
1145
1146 if (getDolGlobalString('MYMODULE_MYOBJECT_ADDON')) {
1147 $mybool = false;
1148
1149 $file = getDolGlobalString('MYMODULE_MYOBJECT_ADDON').".php";
1150 $classname = getDolGlobalString('MYMODULE_MYOBJECT_ADDON');
1151
1152 // Include file with class
1153 $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1154 foreach ($dirmodels as $reldir) {
1155 $dir = dol_buildpath($reldir."core/modules/mymodule/");
1156
1157 // Load file with numbering class (if found)
1158 $mybool |= @include_once $dir.$file;
1159 }
1160
1161 if ($mybool === false) {
1162 dol_print_error('', "Failed to include file ".$file);
1163 return '';
1164 }
1165
1166 if (class_exists($classname)) {
1167 $obj = new $classname();
1168 $numref = $obj->getNextValue($this);
1169
1170 if ($numref != '' && $numref != '-1') {
1171 return $numref;
1172 } else {
1173 $this->error = $obj->error;
1174 //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1175 return "";
1176 }
1177 } else {
1178 print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1179 return "";
1180 }
1181 } else {
1182 print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1183 return "";
1184 }
1185 }
1186
1198 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1199 {
1200 global $conf, $langs;
1201
1202 $result = 0;
1203 $includedocgeneration = 0;
1204
1205 $langs->load("mymodule@mymodule");
1206
1207 if (!dol_strlen($modele)) {
1208 $modele = 'standard_myobject';
1209
1210 if (!empty($this->model_pdf)) {
1211 $modele = $this->model_pdf;
1212 } elseif (getDolGlobalString('MYOBJECT_ADDON_PDF')) {
1213 $modele = getDolGlobalString('MYOBJECT_ADDON_PDF');
1214 }
1215 }
1216
1217 $modelpath = "core/modules/mymodule/doc/";
1218
1219 if ($includedocgeneration && !empty($modele)) {
1220 $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1221 }
1222
1223 return $result;
1224 }
1225
1233 public function doScheduledJob()
1234 {
1235 //global $conf, $langs;
1236
1237 //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlogfile.log';
1238
1239 $error = 0;
1240 $this->output = '';
1241 $this->error = '';
1242
1243 dol_syslog(__METHOD__." start", LOG_INFO);
1244
1245 $now = dol_now();
1246
1247 $this->db->begin();
1248
1249 // ...
1250
1251 $this->db->commit();
1252
1253 dol_syslog(__METHOD__." end", LOG_INFO);
1254
1255 return $error;
1256 }
1257}
1258
1259
1260require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
1261
1266{
1267 // To complete with content of an object MyObjectLine
1268 // We should have a field rowid, fk_myobject and position
1269
1273 public $isextrafieldmanaged = 0;
1274
1280 public function __construct(DoliDB $db)
1281 {
1282 $this->db = $db;
1283 }
1284}
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Definition security.php:604
$object ref
Definition info.php:79
Parent class of all other business classes (invoices, contracts, proposals, orders,...
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
deleteLineCommon(User $user, $idline, $notrigger=false)
Delete a line of object in database.
setErrorsFromObject($object)
setErrorsFromObject
createCommon(User $user, $notrigger=false)
Create object into database.
deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
Delete object in database.
getFieldList($alias='', $excludefields=array())
Function to concat keys of fields.
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.
updateCommon(User $user, $notrigger=false)
Update object into database.
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.
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 for MyObject.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
createFromClone(User $user, $fromid)
Clone an object into another one.
getKanbanView($option='', $arraydata=null)
Return a thumb for kanban views.
getLibStatut($mode=0)
Return the label of the status.
getTooltipContentArray($params)
getTooltipContentArray
reopen($user, $notrigger=0)
Set back to validated status.
setDraft($user, $notrigger=0)
Set draft status.
getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='', $save_lastsearch_value=-1)
Return a link to the object card (with optionaly the picto)
LibStatut($status, $mode=0)
Return the label of a given status.
getNextNumRef()
Returns the reference to the following non used object depending on the active numbering module.
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter=array(), $filtermode='AND')
Load list of objects in memory from the database.
__construct(DoliDB $db)
Constructor.
cancel($user, $notrigger=0)
Set cancel status.
update(User $user, $notrigger=false)
Update object into database.
fetchLines($noextrafields=0)
Load object lines in memory from the database.
info($id)
Load the info information in the object.
doScheduledJob()
Action executed by scheduler CAN BE A CRON TASK.
fetch($id, $ref=null, $noextrafields=0, $nolines=0)
Load object in memory from the database.
getLabelStatus($mode=0)
Return the label of the status.
create(User $user, $notrigger=false)
Create object into database.
deleteLine(User $user, $idline, $notrigger=false)
Delete a line of object in database.
validate($user, $notrigger=0)
Validate object.
getLinesArray()
Create an array of lines.
Class MyObjectLine.
__construct(DoliDB $db)
Constructor.
Class to manage Dolibarr users.
dol_dir_list($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:62
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
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.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.