Passed
Branch develop (96ac0e)
by
unknown
23:19
created

MyObject::info()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 37
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 27
nc 10
nop 1
dl 0
loc 37
rs 8.8657
c 0
b 0
f 0
1
<?php
2
/* Copyright (C) 2017  Laurent Destailleur <[email protected]>
3
 * Copyright (C) ---Put here your own copyright and developer email---
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
 */
18
19
/**
20
 * \file        htdocs/modulebuilder/template/class/myobject.class.php
21
 * \ingroup     mymodule
22
 * \brief       This file is a CRUD class file for MyObject (Create/Read/Update/Delete)
23
 */
24
25
// Put here all includes required by your class file
26
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
27
//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
28
//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
29
30
/**
31
 * Class for MyObject
32
 */
33
class MyObject extends CommonObject
34
{
35
	/**
36
	 * @var string ID of module.
37
	 */
38
	public $module = 'mymodule';
39
40
	/**
41
	 * @var string ID to identify managed object.
42
	 */
43
	public $element = 'myobject';
44
45
	/**
46
	 * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management.
47
	 */
48
	public $table_element = 'mymodule_myobject';
49
50
	/**
51
	 * @var int  Does this object support multicompany module ?
52
	 * 0=No test on entity, 1=Test with field entity, 'field@table'=Test with link by field@table
53
	 */
54
	public $ismultientitymanaged = 0;
55
56
	/**
57
	 * @var int  Does object support extrafields ? 0=No, 1=Yes
58
	 */
59
	public $isextrafieldmanaged = 1;
60
61
	/**
62
	 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
63
	 */
64
	public $picto = 'myobject@mymodule';
65
66
67
	const STATUS_DRAFT = 0;
68
	const STATUS_VALIDATED = 1;
69
	const STATUS_CANCELED = 9;
70
71
72
	/**
73
	 *  'type' field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]', 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter[:Sortfield]]]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'text:none', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password')
74
	 *         Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)"
75
	 *  'label' the translation key.
76
	 *  'picto' is code of a picto to show before value in forms
77
	 *  'enabled' is a condition when the field must be managed (Example: 1 or '$conf->global->MY_SETUP_PARAM)
78
	 *  'position' is the sort order of field.
79
	 *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
80
	 *  'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing)
81
	 *  'noteditable' says if field is not editable (1 or 0)
82
	 *  'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created.
83
	 *  'index' if we want an index in database.
84
	 *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...).
85
	 *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
86
	 *  'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8).
87
	 *  'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200'
88
	 *  'help' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click.
89
	 *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
90
	 *  'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code.
91
	 *  'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar'
92
	 *  'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1.
93
	 *  'comment' is not used. You can store here any text of your choice. It is not used by application.
94
	 *	'validate' is 1 if need to validate with $this->validateField()
95
	 *  'copytoclipboard' is 1 or 2 to allow to add a picto to copy value into clipboard (1=picto after label, 2=picto after value)
96
	 *
97
	 *  Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
98
	 */
99
100
	// BEGIN MODULEBUILDER PROPERTIES
101
	/**
102
	 * @var array  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
103
	 */
104
	public $fields = array(
105
		'rowid'         => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'noteditable'=>1, 'notnull'=> 1, 'index'=>1, 'position'=>1, 'comment'=>'Id', 'css'=>'left'),
106
		'entity'        => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'notnull'=> 1, 'default'=>1, 'index'=>1, 'position'=>10),
107
		'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),
108
		'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),
109
		'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),
110
		'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),
111
		'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'=>1, 'position'=>50, 'notnull'=>-1, 'index'=>1, 'help'=>'LinkToThirparty', 'validate'=>1),
112
		'fk_project'    => array('type'=>'integer:Project:projet/class/project.class.php:1', 'label'=>'Project', 'picto'=>'project', 'enabled'=>1, 'visible'=>-1, 'position'=>52, 'notnull'=>-1, 'index'=>1, 'validate'=>1),
113
		'description'   => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>3, 'position'=>60, 'validate'=>1),
114
		'note_public'   => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>61, 'validate'=>1),
115
		'note_private'  => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>62, 'validate'=>1),
116
		'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'notnull'=> 1, 'position'=>500),
117
		'tms'           => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'notnull'=> 0, 'position'=>501),
118
		//'date_validation '    =>array('type'=>'datetime',     'label'=>'DateCreation',     'enabled'=>1, 'visible'=>-2, 'position'=>502),
119
		'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'),
120
		'fk_user_modif' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'picto'=>'user', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>511),
121
		//'fk_user_valid' => array('type'=>'integer:User:user/class/user.class.php',      'label'=>'UserValidation',        'enabled'=>1, 'visible'=>-1, 'position'=>512),
122
		'last_main_doc' => array('type'=>'varchar(255)', 'label'=>'LastMainDoc', 'enabled'=>1, 'visible'=>0, 'notnull'=>0, 'position'=>600),
123
		'import_key'    => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'index'=>0, 'position'=>1000),
124
		'model_pdf' 	=> array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'notnull'=>-1, 'position'=>1010),
125
		'status'        => array('type'=>'smallint', 'label'=>'Status', 'enabled'=>1, 'visible'=>1, 'notnull'=> 1, 'default'=>0, 'index'=>1, 'position'=>1000, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Validated', 9=>'Canceled'), 'validate'=>1),
126
	);
127
128
	/**
129
	 * @var int ID
130
	 */
131
	public $rowid;
132
133
	/**
134
	 * @var string Ref
135
	 */
136
	public $ref;
137
138
	/**
139
	 * @var int Entity
140
	 */
141
	public $entity;
142
143
	/**
144
	 * @var string label
145
	 */
146
	public $label;
147
148
	/**
149
	 * @var string amount
150
	 */
151
	public $amount;
152
153
	/**
154
	 * @var int Status
155
	 */
156
	public $status;
157
158
	/**
159
	 * @var integer|string date_creation
160
	 */
161
	public $date_creation;
162
163
	/**
164
	 * @var integer tms
165
	 */
166
	public $tms;
167
168
	/**
169
	 * @var int ID
170
	 */
171
	public $fk_user_creat;
172
173
	/**
174
	 * @var int ID
175
	 */
176
	public $fk_user_modif;
177
178
	/**
179
	 * @var string public $last_main_doc
180
	 */
181
	public $last_main_doc;
182
183
	/**
184
	 * @var string import_key
185
	 */
186
	public $import_key;
187
	// END MODULEBUILDER PROPERTIES
188
189
190
	// If this object has a subtable with lines
191
192
	// /**
193
	//  * @var string    Name of subtable line
194
	//  */
195
	// public $table_element_line = 'mymodule_myobjectline';
196
197
	// /**
198
	//  * @var string    Field with ID of parent key if this object has a parent
199
	//  */
200
	// public $fk_element = 'fk_myobject';
201
202
	// /**
203
	//  * @var string    Name of subtable class that manage subtable lines
204
	//  */
205
	// public $class_element_line = 'MyObjectline';
206
207
	// /**
208
	//  * @var array	List of child tables. To test if we can delete object.
209
	//  */
210
	// protected $childtables = array();
211
212
	// /**
213
	//  * @var array    List of child tables. To know object to delete on cascade.
214
	//  *               If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will
215
	//  *               call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object
216
	//  */
217
	// protected $childtablesoncascade = array('mymodule_myobjectdet');
218
219
	// /**
220
	//  * @var MyObjectLine[]     Array of subtable lines
221
	//  */
222
	// public $lines = array();
223
224
225
226
	/**
227
	 * Constructor
228
	 *
229
	 * @param DoliDb $db Database handler
230
	 */
231
	public function __construct(DoliDB $db)
232
	{
233
		global $conf, $langs;
234
235
		$this->db = $db;
236
237
		if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) {
238
			$this->fields['rowid']['visible'] = 0;
239
		}
240
		if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) {
241
			$this->fields['entity']['enabled'] = 0;
242
		}
243
244
		// Example to show how to set values of fields definition dynamically
245
		/*if ($user->rights->mymodule->myobject->read) {
246
			$this->fields['myfield']['visible'] = 1;
247
			$this->fields['myfield']['noteditable'] = 0;
248
		}*/
249
250
		// Unset fields that are disabled
251
		foreach ($this->fields as $key => $val) {
252
			if (isset($val['enabled']) && empty($val['enabled'])) {
253
				unset($this->fields[$key]);
254
			}
255
		}
256
257
		// Translate some data of arrayofkeyval
258
		if (is_object($langs)) {
259
			foreach ($this->fields as $key => $val) {
260
				if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
261
					foreach ($val['arrayofkeyval'] as $key2 => $val2) {
262
						$this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2);
263
					}
264
				}
265
			}
266
		}
267
	}
268
269
	/**
270
	 * Create object into database
271
	 *
272
	 * @param  User $user      User that creates
273
	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
274
	 * @return int             <0 if KO, Id of created object if OK
275
	 */
276
	public function create(User $user, $notrigger = false)
277
	{
278
		$resultcreate = $this->createCommon($user, $notrigger);
279
280
		//$resultvalidate = $this->validate($user, $notrigger);
281
282
		return $resultcreate;
283
	}
284
285
	/**
286
	 * Clone an object into another one
287
	 *
288
	 * @param  	User 	$user      	User that creates
289
	 * @param  	int 	$fromid     Id of object to clone
290
	 * @return 	mixed 				New object created, <0 if KO
291
	 */
292
	public function createFromClone(User $user, $fromid)
293
	{
294
		global $langs, $extrafields;
295
		$error = 0;
296
297
		dol_syslog(__METHOD__, LOG_DEBUG);
298
299
		$object = new self($this->db);
300
301
		$this->db->begin();
302
303
		// Load source object
304
		$result = $object->fetchCommon($fromid);
305
		if ($result > 0 && !empty($object->table_element_line)) {
306
			$object->fetchLines();
307
		}
308
309
		// get lines so they will be clone
310
		//foreach($this->lines as $line)
311
		//	$line->fetch_optionals();
312
313
		// Reset some properties
314
		unset($object->id);
315
		unset($object->fk_user_creat);
316
		unset($object->import_key);
317
318
		// Clear fields
319
		if (property_exists($object, 'ref')) {
320
			$object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default'];
321
		}
322
		if (property_exists($object, 'label')) {
323
			$object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default'];
324
		}
325
		if (property_exists($object, 'status')) {
326
			$object->status = self::STATUS_DRAFT;
327
		}
328
		if (property_exists($object, 'date_creation')) {
329
			$object->date_creation = dol_now();
330
		}
331
		if (property_exists($object, 'date_modification')) {
332
			$object->date_modification = null;
333
		}
334
		// ...
335
		// Clear extrafields that are unique
336
		if (is_array($object->array_options) && count($object->array_options) > 0) {
337
			$extrafields->fetch_name_optionals_label($this->table_element);
338
			foreach ($object->array_options as $key => $option) {
339
				$shortkey = preg_replace('/options_/', '', $key);
340
				if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) {
341
					//var_dump($key); var_dump($clonedObj->array_options[$key]); exit;
342
					unset($object->array_options[$key]);
343
				}
344
			}
345
		}
346
347
		// Create clone
348
		$object->context['createfromclone'] = 'createfromclone';
349
		$result = $object->createCommon($user);
350
		if ($result < 0) {
351
			$error++;
352
			$this->error = $object->error;
353
			$this->errors = $object->errors;
354
		}
355
356
		if (!$error) {
357
			// copy internal contacts
358
			if ($this->copy_linked_contact($object, 'internal') < 0) {
359
				$error++;
360
			}
361
		}
362
363
		if (!$error) {
364
			// copy external contacts if same company
365
			if (property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) {
366
				if ($this->copy_linked_contact($object, 'external') < 0) {
367
					$error++;
368
				}
369
			}
370
		}
371
372
		unset($object->context['createfromclone']);
373
374
		// End
375
		if (!$error) {
376
			$this->db->commit();
377
			return $object;
378
		} else {
379
			$this->db->rollback();
380
			return -1;
381
		}
382
	}
383
384
	/**
385
	 * Load object in memory from the database
386
	 *
387
	 * @param int    $id   Id object
388
	 * @param string $ref  Ref
389
	 * @return int         <0 if KO, 0 if not found, >0 if OK
390
	 */
391
	public function fetch($id, $ref = null)
392
	{
393
		$result = $this->fetchCommon($id, $ref);
394
		if ($result > 0 && !empty($this->table_element_line)) {
395
			$this->fetchLines();
396
		}
397
		return $result;
398
	}
399
400
	/**
401
	 * Load object lines in memory from the database
402
	 *
403
	 * @return int         <0 if KO, 0 if not found, >0 if OK
404
	 */
405
	public function fetchLines()
406
	{
407
		$this->lines = array();
408
409
		$result = $this->fetchLinesCommon();
410
		return $result;
411
	}
412
413
414
	/**
415
	 * Load list of objects in memory from the database.
416
	 *
417
	 * @param  string      $sortorder    Sort Order
418
	 * @param  string      $sortfield    Sort field
419
	 * @param  int         $limit        limit
420
	 * @param  int         $offset       Offset
421
	 * @param  array       $filter       Filter array. Example array('field'=>'valueforlike', 'customurl'=>...)
422
	 * @param  string      $filtermode   Filter mode (AND or OR)
423
	 * @return array|int                 int <0 if KO, array of pages if OK
424
	 */
425
	public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
426
	{
427
		global $conf;
428
429
		dol_syslog(__METHOD__, LOG_DEBUG);
430
431
		$records = array();
432
433
		$sql = 'SELECT ';
434
		$sql .= $this->getFieldList('t');
435
		$sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
436
		if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) {
437
			$sql .= ' WHERE t.entity IN ('.getEntity($this->table_element).')';
438
		} else {
439
			$sql .= ' WHERE 1 = 1';
440
		}
441
		// Manage filter
442
		$sqlwhere = array();
443
		if (count($filter) > 0) {
444
			foreach ($filter as $key => $value) {
445
				if ($key == 't.rowid') {
446
					$sqlwhere[] = $key." = ".((int) $value);
447
				} elseif (in_array($this->fields[$key]['type'], array('date', 'datetime', 'timestamp'))) {
448
					$sqlwhere[] = $key." = '".$this->db->idate($value)."'";
449
				} elseif ($key == 'customsql') {
450
					$sqlwhere[] = $value;
451
				} elseif (strpos($value, '%') === false) {
452
					$sqlwhere[] = $key." IN (".$this->db->sanitize($this->db->escape($value)).")";
453
				} else {
454
					$sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
455
				}
456
			}
457
		}
458
		if (count($sqlwhere) > 0) {
459
			$sql .= " AND (".implode(" ".$filtermode." ", $sqlwhere).")";
460
		}
461
462
		if (!empty($sortfield)) {
463
			$sql .= $this->db->order($sortfield, $sortorder);
464
		}
465
		if (!empty($limit)) {
466
			$sql .= $this->db->plimit($limit, $offset);
467
		}
468
469
		$resql = $this->db->query($sql);
470
		if ($resql) {
471
			$num = $this->db->num_rows($resql);
472
			$i = 0;
473
			while ($i < ($limit ? min($limit, $num) : $num)) {
474
				$obj = $this->db->fetch_object($resql);
475
476
				$record = new self($this->db);
477
				$record->setVarsFromFetchObj($obj);
478
479
				$records[$record->id] = $record;
480
481
				$i++;
482
			}
483
			$this->db->free($resql);
484
485
			return $records;
486
		} else {
487
			$this->errors[] = 'Error '.$this->db->lasterror();
488
			dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
489
490
			return -1;
491
		}
492
	}
493
494
	/**
495
	 * Update object into database
496
	 *
497
	 * @param  User $user      User that modifies
498
	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
499
	 * @return int             <0 if KO, >0 if OK
500
	 */
501
	public function update(User $user, $notrigger = false)
502
	{
503
		return $this->updateCommon($user, $notrigger);
504
	}
505
506
	/**
507
	 * Delete object in database
508
	 *
509
	 * @param User $user       User that deletes
510
	 * @param bool $notrigger  false=launch triggers after, true=disable triggers
511
	 * @return int             <0 if KO, >0 if OK
512
	 */
513
	public function delete(User $user, $notrigger = false)
514
	{
515
		return $this->deleteCommon($user, $notrigger);
516
		//return $this->deleteCommon($user, $notrigger, 1);
517
	}
518
519
	/**
520
	 *  Delete a line of object in database
521
	 *
522
	 *	@param  User	$user       User that delete
523
	 *  @param	int		$idline		Id of line to delete
524
	 *  @param 	bool 	$notrigger  false=launch triggers after, true=disable triggers
525
	 *  @return int         		>0 if OK, <0 if KO
526
	 */
527
	public function deleteLine(User $user, $idline, $notrigger = false)
528
	{
529
		if ($this->status < 0) {
530
			$this->error = 'ErrorDeleteLineNotAllowedByObjectStatus';
531
			return -2;
532
		}
533
534
		return $this->deleteLineCommon($user, $idline, $notrigger);
535
	}
536
537
538
	/**
539
	 *	Validate object
540
	 *
541
	 *	@param		User	$user     		User making status change
542
	 *  @param		int		$notrigger		1=Does not execute triggers, 0= execute triggers
543
	 *	@return  	int						<=0 if OK, 0=Nothing done, >0 if KO
544
	 */
545
	public function validate($user, $notrigger = 0)
546
	{
547
		global $conf, $langs;
548
549
		require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
550
551
		$error = 0;
552
553
		// Protection
554
		if ($this->status == self::STATUS_VALIDATED) {
555
			dol_syslog(get_class($this)."::validate action abandonned: already validated", LOG_WARNING);
556
			return 0;
557
		}
558
559
		/*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->mymodule->myobject->write))
560
		 || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->mymodule->myobject->myobject_advance->validate))))
561
		 {
562
		 $this->error='NotEnoughPermissions';
563
		 dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR);
564
		 return -1;
565
		 }*/
566
567
		$now = dol_now();
568
569
		$this->db->begin();
570
571
		// Define new ref
572
		if (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) { // empty should not happened, but when it occurs, the test save life
573
			$num = $this->getNextNumRef();
574
		} else {
575
			$num = $this->ref;
576
		}
577
		$this->newref = $num;
578
579
		if (!empty($num)) {
580
			// Validate
581
			$sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element;
582
			$sql .= " SET ref = '".$this->db->escape($num)."',";
583
			$sql .= " status = ".self::STATUS_VALIDATED;
584
			if (!empty($this->fields['date_validation'])) {
585
				$sql .= ", date_validation = '".$this->db->idate($now)."'";
586
			}
587
			if (!empty($this->fields['fk_user_valid'])) {
588
				$sql .= ", fk_user_valid = ".((int) $user->id);
589
			}
590
			$sql .= " WHERE rowid = ".((int) $this->id);
591
592
			dol_syslog(get_class($this)."::validate()", LOG_DEBUG);
593
			$resql = $this->db->query($sql);
594
			if (!$resql) {
595
				dol_print_error($this->db);
596
				$this->error = $this->db->lasterror();
597
				$error++;
598
			}
599
600
			if (!$error && !$notrigger) {
601
				// Call trigger
602
				$result = $this->call_trigger('MYOBJECT_VALIDATE', $user);
603
				if ($result < 0) {
604
					$error++;
605
				}
606
				// End call triggers
607
			}
608
		}
609
610
		if (!$error) {
611
			$this->oldref = $this->ref;
612
613
			// Rename directory if dir was a temporary ref
614
			if (preg_match('/^[\(]?PROV/i', $this->ref)) {
615
				// Now we rename also files into index
616
				$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)."'";
617
				$sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'myobject/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
618
				$resql = $this->db->query($sql);
619
				if (!$resql) {
620
					$error++; $this->error = $this->db->lasterror();
621
				}
622
623
				// We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
624
				$oldref = dol_sanitizeFileName($this->ref);
625
				$newref = dol_sanitizeFileName($num);
626
				$dirsource = $conf->mymodule->dir_output.'/myobject/'.$oldref;
627
				$dirdest = $conf->mymodule->dir_output.'/myobject/'.$newref;
628
				if (!$error && file_exists($dirsource)) {
629
					dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest);
630
631
					if (@rename($dirsource, $dirdest)) {
632
						dol_syslog("Rename ok");
633
						// Rename docs starting with $oldref with $newref
634
						$listoffiles = dol_dir_list($conf->mymodule->dir_output.'/myobject/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
635
						foreach ($listoffiles as $fileentry) {
636
							$dirsource = $fileentry['name'];
637
							$dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
638
							$dirsource = $fileentry['path'].'/'.$dirsource;
639
							$dirdest = $fileentry['path'].'/'.$dirdest;
640
							@rename($dirsource, $dirdest);
641
						}
642
					}
643
				}
644
			}
645
		}
646
647
		// Set new ref and current status
648
		if (!$error) {
649
			$this->ref = $num;
650
			$this->status = self::STATUS_VALIDATED;
651
		}
652
653
		if (!$error) {
654
			$this->db->commit();
655
			return 1;
656
		} else {
657
			$this->db->rollback();
658
			return -1;
659
		}
660
	}
661
662
663
	/**
664
	 *	Set draft status
665
	 *
666
	 *	@param	User	$user			Object user that modify
667
	 *  @param	int		$notrigger		1=Does not execute triggers, 0=Execute triggers
668
	 *	@return	int						<0 if KO, >0 if OK
669
	 */
670
	public function setDraft($user, $notrigger = 0)
671
	{
672
		// Protection
673
		if ($this->status <= self::STATUS_DRAFT) {
674
			return 0;
675
		}
676
677
		/*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->mymodule->write))
678
		 || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->mymodule->mymodule_advance->validate))))
679
		 {
680
		 $this->error='Permission denied';
681
		 return -1;
682
		 }*/
683
684
		return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'MYOBJECT_UNVALIDATE');
685
	}
686
687
	/**
688
	 *	Set cancel status
689
	 *
690
	 *	@param	User	$user			Object user that modify
691
	 *  @param	int		$notrigger		1=Does not execute triggers, 0=Execute triggers
692
	 *	@return	int						<0 if KO, 0=Nothing done, >0 if OK
693
	 */
694
	public function cancel($user, $notrigger = 0)
695
	{
696
		// Protection
697
		if ($this->status != self::STATUS_VALIDATED) {
698
			return 0;
699
		}
700
701
		/*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->mymodule->write))
702
		 || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->mymodule->mymodule_advance->validate))))
703
		 {
704
		 $this->error='Permission denied';
705
		 return -1;
706
		 }*/
707
708
		return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'MYOBJECT_CANCEL');
709
	}
710
711
	/**
712
	 *	Set back to validated status
713
	 *
714
	 *	@param	User	$user			Object user that modify
715
	 *  @param	int		$notrigger		1=Does not execute triggers, 0=Execute triggers
716
	 *	@return	int						<0 if KO, 0=Nothing done, >0 if OK
717
	 */
718
	public function reopen($user, $notrigger = 0)
719
	{
720
		// Protection
721
		if ($this->status != self::STATUS_CANCELED) {
722
			return 0;
723
		}
724
725
		/*if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->mymodule->write))
726
		 || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->mymodule->mymodule_advance->validate))))
727
		 {
728
		 $this->error='Permission denied';
729
		 return -1;
730
		 }*/
731
732
		return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'MYOBJECT_REOPEN');
733
	}
734
735
	/**
736
	 *  Return a link to the object card (with optionaly the picto)
737
	 *
738
	 *  @param  int     $withpicto                  Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
739
	 *  @param  string  $option                     On what the link point to ('nolink', ...)
740
	 *  @param  int     $notooltip                  1=Disable tooltip
741
	 *  @param  string  $morecss                    Add more css on link
742
	 *  @param  int     $save_lastsearch_value      -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
743
	 *  @return	string                              String with URL
744
	 */
745
	public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1)
746
	{
747
		global $conf, $langs, $hookmanager;
748
749
		if (!empty($conf->dol_no_mouse_hover)) {
750
			$notooltip = 1; // Force disable tooltips
751
		}
752
753
		$result = '';
754
755
		$label = img_picto('', $this->picto).' <u>'.$langs->trans("MyObject").'</u>';
756
		if (isset($this->status)) {
757
			$label .= ' '.$this->getLibStatut(5);
758
		}
759
		$label .= '<br>';
760
		$label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
761
762
		$url = dol_buildpath('/mymodule/myobject_card.php', 1).'?id='.$this->id;
763
764
		if ($option != 'nolink') {
765
			// Add param to save lastsearch_values or not
766
			$add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
767
			if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
768
				$add_save_lastsearch_values = 1;
769
			}
770
			if ($add_save_lastsearch_values) {
771
				$url .= '&save_lastsearch_values=1';
772
			}
773
		}
774
775
		$linkclose = '';
776
		if (empty($notooltip)) {
777
			if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
778
				$label = $langs->trans("ShowMyObject");
779
				$linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
780
			}
781
			$linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
782
			$linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
783
		} else {
784
			$linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
785
		}
786
787
		if ($option == 'nolink') {
788
			$linkstart = '<span';
789
		} else {
790
			$linkstart = '<a href="'.$url.'"';
791
		}
792
		$linkstart .= $linkclose.'>';
793
		if ($option == 'nolink') {
794
			$linkend = '</span>';
795
		} else {
796
			$linkend = '</a>';
797
		}
798
799
		$result .= $linkstart;
800
801
		if (empty($this->showphoto_on_popup)) {
802
			if ($withpicto) {
803
				$result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
804
			}
805
		} else {
806
			if ($withpicto) {
807
				require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
808
809
				list($class, $module) = explode('@', $this->picto);
810
				$upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref);
811
				$filearray = dol_dir_list($upload_dir, "files");
812
				$filename = $filearray[0]['name'];
813
				if (!empty($filename)) {
814
					$pospoint = strpos($filearray[0]['name'], '.');
815
816
					$pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint);
817
					if (empty($conf->global->{strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS'})) {
818
						$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>';
819
					} else {
820
						$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>';
821
					}
822
823
					$result .= '</div>';
824
				} else {
825
					$result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
826
				}
827
			}
828
		}
829
830
		if ($withpicto != 2) {
831
			$result .= $this->ref;
832
		}
833
834
		$result .= $linkend;
835
		//if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
836
837
		global $action, $hookmanager;
838
		$hookmanager->initHooks(array('myobjectdao'));
839
		$parameters = array('id'=>$this->id, 'getnomurl'=>$result);
840
		$reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
841
		if ($reshook > 0) {
842
			$result = $hookmanager->resPrint;
843
		} else {
844
			$result .= $hookmanager->resPrint;
845
		}
846
847
		return $result;
848
	}
849
850
	/**
851
	 *  Return the label of the status
852
	 *
853
	 *  @param  int		$mode          0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
854
	 *  @return	string 			       Label of status
855
	 */
856
	public function getLabelStatus($mode = 0)
857
	{
858
		return $this->LibStatut($this->status, $mode);
859
	}
860
861
	/**
862
	 *  Return the label of the status
863
	 *
864
	 *  @param  int		$mode          0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
865
	 *  @return	string 			       Label of status
866
	 */
867
	public function getLibStatut($mode = 0)
868
	{
869
		return $this->LibStatut($this->status, $mode);
870
	}
871
872
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
873
	/**
874
	 *  Return the status
875
	 *
876
	 *  @param	int		$status        Id status
877
	 *  @param  int		$mode          0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
878
	 *  @return string 			       Label of status
879
	 */
880
	public function LibStatut($status, $mode = 0)
881
	{
882
		// phpcs:enable
883
		if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
884
			global $langs;
885
			//$langs->load("mymodule@mymodule");
886
			$this->labelStatus[self::STATUS_DRAFT] = $langs->trans('Draft');
887
			$this->labelStatus[self::STATUS_VALIDATED] = $langs->trans('Enabled');
888
			$this->labelStatus[self::STATUS_CANCELED] = $langs->trans('Disabled');
889
			$this->labelStatusShort[self::STATUS_DRAFT] = $langs->trans('Draft');
890
			$this->labelStatusShort[self::STATUS_VALIDATED] = $langs->trans('Enabled');
891
			$this->labelStatusShort[self::STATUS_CANCELED] = $langs->trans('Disabled');
892
		}
893
894
		$statusType = 'status'.$status;
895
		//if ($status == self::STATUS_VALIDATED) $statusType = 'status1';
896
		if ($status == self::STATUS_CANCELED) {
897
			$statusType = 'status6';
898
		}
899
900
		return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
901
	}
902
903
	/**
904
	 *	Load the info information in the object
905
	 *
906
	 *	@param  int		$id       Id of object
907
	 *	@return	void
908
	 */
909
	public function info($id)
910
	{
911
		$sql = 'SELECT rowid, date_creation as datec, tms as datem,';
912
		$sql .= ' fk_user_creat, fk_user_modif';
913
		$sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
914
		$sql .= ' WHERE t.rowid = '.((int) $id);
915
		$result = $this->db->query($sql);
916
		if ($result) {
917
			if ($this->db->num_rows($result)) {
918
				$obj = $this->db->fetch_object($result);
919
				$this->id = $obj->rowid;
920
				if ($obj->fk_user_author) {
921
					$cuser = new User($this->db);
922
					$cuser->fetch($obj->fk_user_author);
923
					$this->user_creation = $cuser;
924
				}
925
926
				if ($obj->fk_user_valid) {
927
					$vuser = new User($this->db);
928
					$vuser->fetch($obj->fk_user_valid);
929
					$this->user_validation = $vuser;
930
				}
931
932
				if ($obj->fk_user_cloture) {
933
					$cluser = new User($this->db);
934
					$cluser->fetch($obj->fk_user_cloture);
935
					$this->user_cloture = $cluser;
936
				}
937
938
				$this->date_creation     = $this->db->jdate($obj->datec);
939
				$this->date_modification = $this->db->jdate($obj->datem);
940
				$this->date_validation   = $this->db->jdate($obj->datev);
941
			}
942
943
			$this->db->free($result);
944
		} else {
945
			dol_print_error($this->db);
946
		}
947
	}
948
949
	/**
950
	 * Initialise object with example values
951
	 * Id must be 0 if object instance is a specimen
952
	 *
953
	 * @return void
954
	 */
955
	public function initAsSpecimen()
956
	{
957
		// Set here init that are not commonf fields
958
		// $this->property1 = ...
959
		// $this->property2 = ...
960
961
		$this->initAsSpecimenCommon();
962
	}
963
964
	/**
965
	 * 	Create an array of lines
966
	 *
967
	 * 	@return array|int		array of lines if OK, <0 if KO
968
	 */
969
	public function getLinesArray()
970
	{
971
		$this->lines = array();
972
973
		$objectline = new MyObjectLine($this->db);
974
		$result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_myobject = '.((int) $this->id)));
0 ignored issues
show
Bug introduced by
The method fetchAll() does not exist on MyObjectLine. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

974
		/** @scrutinizer ignore-call */ 
975
  $result = $objectline->fetchAll('ASC', 'position', 0, 0, array('customsql'=>'fk_myobject = '.((int) $this->id)));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
975
976
		if (is_numeric($result)) {
977
			$this->error = $this->error;
978
			$this->errors = $this->errors;
979
			return $result;
980
		} else {
981
			$this->lines = $result;
982
			return $this->lines;
983
		}
984
	}
985
986
	/**
987
	 *  Returns the reference to the following non used object depending on the active numbering module.
988
	 *
989
	 *  @return string      		Object free reference
990
	 */
991
	public function getNextNumRef()
992
	{
993
		global $langs, $conf;
994
		$langs->load("mymodule@mymodule");
995
996
		if (empty($conf->global->MYMODULE_MYOBJECT_ADDON)) {
997
			$conf->global->MYMODULE_MYOBJECT_ADDON = 'mod_myobject_standard';
998
		}
999
1000
		if (!empty($conf->global->MYMODULE_MYOBJECT_ADDON)) {
1001
			$mybool = false;
1002
1003
			$file = $conf->global->MYMODULE_MYOBJECT_ADDON.".php";
1004
			$classname = $conf->global->MYMODULE_MYOBJECT_ADDON;
1005
1006
			// Include file with class
1007
			$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
1008
			foreach ($dirmodels as $reldir) {
1009
				$dir = dol_buildpath($reldir."core/modules/mymodule/");
1010
1011
				// Load file with numbering class (if found)
1012
				$mybool |= @include_once $dir.$file;
1013
			}
1014
1015
			if ($mybool === false) {
1016
				dol_print_error('', "Failed to include file ".$file);
1017
				return '';
1018
			}
1019
1020
			if (class_exists($classname)) {
1021
				$obj = new $classname();
1022
				$numref = $obj->getNextValue($this);
1023
1024
				if ($numref != '' && $numref != '-1') {
1025
					return $numref;
1026
				} else {
1027
					$this->error = $obj->error;
1028
					//dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error);
1029
					return "";
1030
				}
1031
			} else {
1032
				print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname;
1033
				return "";
1034
			}
1035
		} else {
1036
			print $langs->trans("ErrorNumberingModuleNotSetup", $this->element);
1037
			return "";
1038
		}
1039
	}
1040
1041
	/**
1042
	 *  Create a document onto disk according to template module.
1043
	 *
1044
	 *  @param	    string		$modele			Force template to use ('' to not force)
1045
	 *  @param		Translate	$outputlangs	objet lang a utiliser pour traduction
1046
	 *  @param      int			$hidedetails    Hide details of lines
1047
	 *  @param      int			$hidedesc       Hide description
1048
	 *  @param      int			$hideref        Hide ref
1049
	 *  @param      null|array  $moreparams     Array to provide more information
1050
	 *  @return     int         				0 if KO, 1 if OK
1051
	 */
1052
	public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
1053
	{
1054
		global $conf, $langs;
1055
1056
		$result = 0;
1057
		$includedocgeneration = 0;
1058
1059
		$langs->load("mymodule@mymodule");
1060
1061
		if (!dol_strlen($modele)) {
1062
			$modele = 'standard_myobject';
1063
1064
			if (!empty($this->model_pdf)) {
1065
				$modele = $this->model_pdf;
1066
			} elseif (!empty($conf->global->MYOBJECT_ADDON_PDF)) {
1067
				$modele = $conf->global->MYOBJECT_ADDON_PDF;
1068
			}
1069
		}
1070
1071
		$modelpath = "core/modules/mymodule/doc/";
1072
1073
		if ($includedocgeneration && !empty($modele)) {
1074
			$result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1075
		}
1076
1077
		return $result;
1078
	}
1079
1080
	/**
1081
	 * Action executed by scheduler
1082
	 * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters'
1083
	 * Use public function doScheduledJob($param1, $param2, ...) to get parameters
1084
	 *
1085
	 * @return	int			0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK)
1086
	 */
1087
	public function doScheduledJob()
1088
	{
1089
		global $conf, $langs;
1090
1091
		//$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log';
1092
1093
		$error = 0;
1094
		$this->output = '';
1095
		$this->error = '';
1096
1097
		dol_syslog(__METHOD__, LOG_DEBUG);
1098
1099
		$now = dol_now();
1100
1101
		$this->db->begin();
1102
1103
		// ...
1104
1105
		$this->db->commit();
1106
1107
		return $error;
1108
	}
1109
}
1110
1111
1112
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php';
1113
1114
/**
1115
 * Class MyObjectLine. You can also remove this and generate a CRUD class for lines objects.
1116
 */
1117
class MyObjectLine extends CommonObjectLine
1118
{
1119
	// To complete with content of an object MyObjectLine
1120
	// We should have a field rowid, fk_myobject and position
1121
1122
	/**
1123
	 * @var int  Does object support extrafields ? 0=No, 1=Yes
1124
	 */
1125
	public $isextrafieldmanaged = 0;
1126
1127
	/**
1128
	 * Constructor
1129
	 *
1130
	 * @param DoliDb $db Database handler
1131
	 */
1132
	public function __construct(DoliDB $db)
1133
	{
1134
		$this->db = $db;
1135
	}
1136
}
1137