Completed
Branch develop (bb7c03)
by
unknown
34:20
created

BlockedLog::getLog()   D

Complexity

Conditions 11
Paths 256

Size

Total Lines 59
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 31
nc 256
nop 7
dl 0
loc 59
rs 4.7191
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* Copyright (C) 2017 ATM Consulting <[email protected]>
3
 * Copyright (C) 2017 Laurent Destailleur <[email protected]>
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 <http://www.gnu.org/licenses/>.
17
 *
18
 * See https://medium.com/@lhartikk/a-blockchain-in-200-lines-of-code-963cc1cc0e54
19
 */
20
21
/**
22
 *	Class to manage Blocked Log
23
 */
24
25
class BlockedLog
26
{
27
	/**
28
	 * Id of the log
29
	 * @var int
30
	 */
31
	public $id;
32
33
	public $error = '';
34
	public $errors = array();
35
36
	/**
37
	 * Unique fingerprint of the log
38
	 * @var string
39
	 */
40
	public $signature = '';
41
42
	/**
43
	 * Unique fingerprint of the line log content
44
	 * @var string
45
	 */
46
	public $signature_line = '';
47
48
	public $amounts = null;
49
50
	/**
51
	 * trigger action
52
	 * @var string
53
	 */
54
	public $action = '';
55
56
	/**
57
	 * Object element
58
	 * @var string
59
	 */
60
	public $element = '';
61
62
	/**
63
	 * Object id
64
	 * @var int
65
	 */
66
	public $fk_object = 0;
67
68
	/**
69
	 * Log certified by remote authority or not
70
	 * @var boolean
71
	 */
72
	public $certified = false;
73
74
	/**
75
	 * Author
76
	 * @var int
77
	 */
78
	public $fk_user = 0;
79
80
	public $date_object = 0;
81
82
	public $ref_object = '';
83
84
	public $object_data = null;
85
86
87
88
	/**
89
	 *      Constructor
90
	 *
91
	 *      @param		DoliDB		$db      Database handler
92
	 */
93
	public function __construct(DoliDB $db)
94
	{
95
		$this->db = $db;
96
97
	}
98
99
	/**
100
	 *      try to retrieve logged object link
101
	 */
102
	public function getObjectLink()
103
	{
104
		global $langs;
105
106
		if($this->element === 'facture') {
107
			require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
108
109
			$object = new Facture($this->db);
110
			if($object->fetch($this->fk_object)>0) {
111
				return $object->getNomUrl(1);
112
			}
113
			else{
114
				$this->error++;
115
			}
116
		}
117
		if($this->element === 'invoice_supplier') {
118
			require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
119
120
			$object = new FactureFournisseur($this->db);
121
			if($object->fetch($this->fk_object)>0) {
122
				return $object->getNomUrl(1);
123
			}
124
			else{
125
				$this->error++;
126
			}
127
		}
128
		else if($this->element === 'payment') {
129
			require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
130
131
			$object = new Paiement($this->db);
132
			if($object->fetch($this->fk_object)>0) {
133
				return $object->getNomUrl(1);
134
			}
135
			else{
136
				$this->error++;
137
			}
138
		}
139
		else if($this->element === 'payment_supplier') {
140
			require_once DOL_DOCUMENT_ROOT.'/fourn/class/paiementfourn.class.php';
141
142
			$object = new PaiementFourn($this->db);
143
			if($object->fetch($this->fk_object)>0) {
144
				return $object->getNomUrl(1);
145
			}
146
			else{
147
				$this->error++;
148
			}
149
		}
150
151
		return '<i class="opacitymedium">'.$langs->trans('ImpossibleToReloadObject', $this->element, $this->fk_object).'</i>';
152
153
	}
154
155
	/**
156
	 *      try to retrieve user author
157
	 */
158
	public function getUser()
159
	{
160
		global $langs, $cachedUser;
161
162
		if(empty($cachedUser))$cachedUser=array();
163
164
		if(empty($cachedUser[$this->fk_user])) {
165
			$u=new User($this->db);
166
			if($u->fetch($this->fk_user)>0) {
167
				$cachedUser[$this->fk_user] = $u;
168
			}
169
		}
170
171
		if(!empty($cachedUser[$this->fk_user])) {
172
			return $cachedUser[$this->fk_user]->getNomUrl(1);
173
		}
174
175
		return $langs->trans('ImpossibleToRetrieveUser', $this->fk_user);
176
	}
177
178
	/**
179
	 *      Populate properties of log from object data
180
	 *
181
	 *      @param		Object		$object      object to store
182
	 *      @param		string		$action      action
183
	 *      @param		string		$amounts     amounts
184
	 */
185
	public function setObjectData(&$object, $action, $amounts)
186
	{
187
		global $langs, $user, $mysoc;
188
189
		// Generic fields
190
191
		// action
192
		$this->action = $action;
193
		// amount
194
		$this->amounts= $amounts;
195
		// date
196
		if ($object->element == 'payment' || $object->element == 'payment_supplier')
197
		{
198
			$this->date_object = $object->datepaye;
199
		}
200
		elseif ($object->element=='payment_salary')
201
		{
202
			$this->date_object = $object->datev;
203
		}
204
		else {
205
			$this->date_object = $object->date;
206
		}
207
		// ref
208
		$this->ref_object = ((! empty($object->newref)) ? $object->newref : $object->ref);		// newref is set when validating a draft, ref is set in other cases
209
		// type of object
210
		$this->element = $object->element;
211
		// id of object
212
		$this->fk_object = $object->id;
213
214
		$this->object_data=new stdClass();
215
216
		// Add thirdparty info
217
218
		if (empty($object->thirdparty) && method_exists($object, 'fetch_thirdparty')) $object->fetch_thirdparty();
219
220
		if (! empty($object->thirdparty))
221
		{
222
			$this->object_data->thirdparty = new stdClass();
223
224
			foreach($object->thirdparty as $key=>$value)
225
			{
226
				if (in_array($key, array('fields'))) continue;	// Discard some properties
227
				if (! in_array($key, array(
228
				'name','name_alias','ref_ext','address','zip','town','state_code','country_code','idprof1','idprof2','idprof3','idprof4','idprof5','idprof6','phone','fax','email','barcode',
229
				'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
230
				))) continue;								// Discard if not into a dedicated list
231
				if (!is_object($value)) $this->object_data->thirdparty->{$key} = $value;
232
			}
233
		}
234
235
		// Add company info
236
		if (! empty($mysoc))
237
		{
238
			$this->object_data->mycompany = new stdClass();
239
240
			foreach($mysoc as $key=>$value)
241
			{
242
				if (in_array($key, array('fields'))) continue;	// Discard some properties
243
				if (! in_array($key, array(
244
				'name','name_alias','ref_ext','address','zip','town','state_code','country_code','idprof1','idprof2','idprof3','idprof4','idprof5','idprof6','phone','fax','email','barcode',
245
				'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
246
				))) continue;									// Discard if not into a dedicated list
247
				if (!is_object($value)) $this->object_data->mycompany->{$key} = $value;
248
			}
249
		}
250
251
		// Add user info
252
253
		$this->fk_user = $user->id;
254
		$this->user_fullname = $user->getFullName($langs);
255
256
		// Field specific to object
257
258
		if ($this->element == 'facture')
259
		{
260
			$this->object_data->total_ht 	= (double) $object->total_ht;
261
			$this->object_data->total_tva	= (double) $object->total_tva;
262
			$this->object_data->total_ttc	= (double) $object->total_ttc;
263
			$this->object_data->total_localtax1 = (double) $object->total_localtax1;
264
			$this->object_data->total_localtax2 = (double) $object->total_localtax2;
265
266
			$this->object_data->revenue_stamp = (double) $object->revenue_stamp;
267
			$this->object_data->date_pointoftax = (double) $object->date_pointoftax;
268
			$this->object_data->note_public	= (double) $object->note_public;
269
		}
270
		if($this->element == 'invoice_supplier') {
271
			if(empty($object->thirdparty))$object->fetch_thirdparty();
272
			$this->object_data->thirdparty = new stdClass();
273
274
			foreach($object->thirdparty as $key=>$value) {
275
				if(!is_object($value)) $this->object_data->thirdparty->{$key} = $value;
276
			}
277
278
			$this->object_data->total_ht 	= (double) $object->total_ht;
279
			$this->object_data->total_tva	= (double) $object->total_tva;
280
			$this->object_data->total_ttc	= (double) $object->total_ttc;
281
			$this->object_data->total_localtax1 = (double) $object->total_localtax1;
282
			$this->object_data->total_localtax2 = (double) $object->total_localtax2;
283
284
			$this->object_data->revenue_stamp = (double) $object->revenue_stamp;
285
			$this->object_data->date_pointoftax = (double) $object->date_pointoftax;
286
			$this->object_data->note_public	= (double) $object->note_public;
287
		}
288
		elseif ($this->element == 'payment'|| $object->element == 'payment_supplier')
289
		{
290
			$this->object_data->amounts = $object->amounts;
291
		}
292
		elseif($this->element == 'payment_salary')
293
		{
294
			$this->object_data->amounts = array($object->amount);
295
		}
296
	}
297
298
	/**
299
	 *	Get object from database
300
	 *
301
	 *	@param      int		$id       	Id of object to load
302
	 *	@return     int         			>0 if OK, <0 if KO, 0 if not found
303
	 */
304
	public function fetch($id) {
305
306
		global $langs;
307
308
		dol_syslog(get_class($this)."::fetch id=".$id, LOG_DEBUG);
309
310
		if (empty($id))
311
		{
312
			$this->error='BadParameter';
313
			return -1;
314
		}
315
316
		$langs->load("blockedlog");
317
318
		$sql = "SELECT b.rowid, b.date_creation, b.signature, b.signature_line, b.amounts, b.action, b.element, b.fk_object, b.certified, b.tms, b.fk_user, b.user_fullname, b.date_object, b.ref_object, b.object_data";
319
		$sql.= " FROM ".MAIN_DB_PREFIX."blockedlog as b";
320
		if ($id) $sql.= " WHERE b.rowid = ". $id;
321
322
		$resql=$this->db->query($sql);
323
		if ($resql)
324
		{
325
			if ($this->db->num_rows($resql))
326
			{
327
				$obj = $this->db->fetch_object($resql);
328
329
				$this->id				= $obj->rowid;
330
				$this->ref				= $obj->rowid;
331
332
				$this->date_creation    = $this->db->jdate($obj->date_creation);
333
				$this->tms				= $this->db->jdate($obj->tms);
334
335
				$this->amounts			= (double) $obj->amounts;
336
				$this->action			= $obj->action;
337
				$this->element			= $obj->element;
338
339
				$this->fk_object		= $obj->fk_object;
340
				$this->date_object		= $this->db->jdate($obj->date_object);
341
				$this->ref_object		= $obj->ref_object;
342
343
				$this->fk_user 			= $obj->fk_user;
344
				$this->user_fullname	= $obj->user_fullname;
345
346
				$this->object_data		= unserialize($obj->object_data);
347
348
				$this->signature		= $obj->signature;
349
				$this->signature_line	= $obj->signature_line;
350
				$this->certified		= ($obj->certified == 1);
351
352
				return 1;
353
			}
354
			else
355
			{
356
				$this->error=$langs->trans("RecordNotFound");
357
				return 0;
358
			}
359
		}
360
		else
361
		{
362
			$this->error=$this->db->error();
363
			return -1;
364
		}
365
366
	}
367
368
	/**
369
	 *	Set block certified by authority
370
	 *
371
	 *	@return	boolean
372
	 */
373
	public function setCertified() {
374
375
		$res = $this->db->query("UPDATE ".MAIN_DB_PREFIX."blockedlog SET certified=1 WHERE rowid=".$this->id);
376
		if($res===false) return false;
377
378
		return true;
379
380
381
	}
382
383
	/**
384
	 *	Create blocked log in database.
385
	 *
386
	 *	@param	User	$user      		Object user that create
387
	 *	@return	int						<0 if KO, >0 if OK
388
	 */
389
	public function create($user) {
390
391
		global $conf,$langs,$hookmanager;
392
393
		$langs->load('blockedlog');
394
395
		$error=0;
396
397
		// Clean data
398
		$this->amounts=(double) $this->amounts;
399
400
		dol_syslog(get_class($this).'::create action='.$this->action.' fk_user='.$this->fk_user.' user_fullname='.$this->user_fullname, LOG_DEBUG);
401
402
		// Check parameters/properties
403
		if (is_null($this->amounts))
404
		{
405
			$this->error=$langs->trans("BlockLogNeedAmountsValue");
406
			dol_syslog($this->error, LOG_WARNING);
407
			return -1;
408
		}
409
410
		if(empty($this->element)) {
411
			$this->error=$langs->trans("BlockLogNeedElement");
412
			dol_syslog($this->error, LOG_WARNING);
413
			return -2;
414
		}
415
416
		if (empty($this->action) || empty($this->fk_user) || empty($this->user_fullname)) {
417
			$this->error=$langs->trans("BadParameterWhenCallingCreateOfBlockedLog");
418
			dol_syslog($this->error, LOG_WARNING);
419
			return -3;
420
		}
421
422
		$this->date_creation = dol_now();
423
424
		$this->db->begin();
425
426
		$previoushash = $this->getPreviousHash(1);	// This get last record and lock database until insert is done
427
428
		$keyforsignature = $this->buildKeyForSignature();
429
430
		$this->signature_line = dol_hash($keyforsignature, '5');		// Not really usefull
431
		$this->signature = dol_hash($previoushash . $keyforsignature, '5');
432
		//var_dump($keyforsignature);var_dump($previoushash);var_dump($this->signature_line);var_dump($this->signature);
433
434
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."blockedlog (";
435
		$sql.= " date_creation,";
436
		$sql.= " action,";
437
		$sql.= " amounts,";
438
		$sql.= " signature,";
439
		$sql.= " signature_line,";
440
		$sql.= " element,";
441
		$sql.= " fk_object,";
442
		$sql.= " date_object,";
443
		$sql.= " ref_object,";
444
		$sql.= " object_data,";
445
		$sql.= " certified,";
446
		$sql.= " fk_user,";
447
		$sql.= " user_fullname,";
448
		$sql.= " entity";
449
		$sql.= ") VALUES (";
450
		$sql.= "'".$this->db->idate($this->date_creation)."',";
451
		$sql.= "'".$this->db->escape($this->action)."',";
452
		$sql.= $this->amounts.",";
453
		$sql.= "'".$this->db->escape($this->signature)."',";
454
		$sql.= "'".$this->db->escape($this->signature_line)."',";
455
		$sql.= "'".$this->db->escape($this->element)."',";
456
		$sql.= $this->fk_object.",";
457
		$sql.= "'".$this->db->idate($this->date_object)."',";
458
		$sql.= "'".$this->db->escape($this->ref_object)."',";
459
		$sql.= "'".$this->db->escape(serialize($this->object_data))."',";
460
		$sql.= "0,";
461
		$sql.= $this->fk_user.",";
462
		$sql.= "'".$this->db->escape($this->user_fullname)."',";
463
		$sql.= $conf->entity;
464
		$sql.= ")";
465
466
		$res = $this->db->query($sql);
467
		if ($res)
468
		{
469
			$id = $this->db->last_insert_id(MAIN_DB_PREFIX."blockedlog");
470
471
			if ($id > 0)
472
			{
473
				$this->id = $id;
474
475
				$this->db->commit();
476
477
				return $this->id;
478
			}
479
			else
480
			{
481
				$this->db->rollback();
482
				return -2;
483
			}
484
		}
485
		else
486
		{
487
			$this->error=$this->db->error();
488
			$this->db->rollback();
489
			return -1;
490
		}
491
492
		// The commit will release the lock so we can insert nex record
493
	}
494
495
	/**
496
	 *	Check if current signature still correct compare to the chain
497
	 *
498
	 *	@return	boolean			True if OK, False if KO
499
	 */
500
	public function checkSignature()
501
	{
502
503
		//$oldblockedlog = new BlockedLog($this->db);
504
		//$previousrecord = $oldblockedlog->fetch($this->id - 1);
505
		$previoushash = $this->getPreviousHash(0, $this->id);
506
507
		// Recalculate hash
508
		$keyforsignature = $this->buildKeyForSignature();
509
		$signature_line = dol_hash($keyforsignature, '5');		// Not really usefull
510
		$signature = dol_hash($previoushash . $keyforsignature, '5');
511
		//var_dump($previoushash); var_dump($keyforsignature); var_dump($signature_line); var_dump($signature);
512
513
		$res = ($signature === $this->signature);
514
515
		if (!$res) {
516
			$this->error = 'Signature KO';
517
		}
518
519
		return $res;
520
	}
521
522
	/**
523
	 * Return a string for signature
524
	 *
525
	 * @return string		Key for signature
526
	 */
527
	private function buildKeyForSignature()
528
	{
529
		//print_r($this->object_data);
530
		return $this->date_creation.'|'.$this->action.'|'.$this->amounts.'|'.$this->ref_object.'|'.$this->date_object.'|'.$this->user_fullname.'|'.print_r($this->object_data, true);
531
	}
532
533
534
	/**
535
	 *	Get previous signature/hash in chain
536
	 *
537
	 *	@param int	$withlock		1=With a lock
538
	 *	@param int	$beforeid		Before id
539
	 *  @return	string				Hash of last record
540
	 */
541
	 private function getPreviousHash($withlock=0, $beforeid=0)
542
	 {
543
		global $conf;
544
545
		$previoussignature='';
546
547
	 	$sql="SELECT rowid, signature FROM ".MAIN_DB_PREFIX."blockedlog WHERE entity=".$conf->entity;
548
	 	if ($beforeid) $sql.= " AND rowid < ".(int) $beforeid;
549
	 	$sql.=" ORDER BY rowid DESC LIMIT 1";
550
	 	$sql.=($withlock ? " FOR UPDATE ": "");
551
552
	 	$resql = $this->db->query($sql);
553
	 	if ($resql) {
554
	 		$obj = $this->db->fetch_object($resql);
555
	 		if ($obj)
556
	 		{
557
	 			$previoussignature = $obj->signature;
558
	 		}
559
	 	}
560
	 	else
561
	 	{
562
	 		dol_print_error($this->db);
563
	 		exit;
564
	 	}
565
566
	 	if (empty($previoussignature))
567
	 	{
568
			// First signature line (line 0)
569
	 		$previoussignature = $this->getSignature();
570
	 	}
571
572
	 	return $previoussignature;
573
	}
574
575
	/**
576
	 *	Return array of log objects (with criterias)
577
	 *
578
	 *	@param	string 	$element      	element to search
579
	 *	@param	int 	$fk_object		id of object to search
580
	 *	@param	int 	$limit      	max number of element, 0 for all
581
	 *	@param	string 	$sortfield     	sort field
582
	 *	@param	string 	$sortorder     	sort order
583
	 *	@param	int 	$search_start   start time limit
584
	 *	@param	int 	$search_end     end time limit
585
	 *	@return	array					array of object log
586
	 */
587
	public function getLog($element, $fk_object, $limit = 0, $sortfield = '', $sortorder = '', $search_start = -1, $search_end = -1)
588
	{
589
		global $conf, $cachedlogs;
590
591
		/* $cachedlogs allow fastest search */
592
		if (empty($cachedlogs)) $cachedlogs=array();
593
594
		if ($element=='all') {
595
596
	 		$sql="SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
597
	         WHERE entity=".$conf->entity;
598
599
		}
600
		else if ($element=='not_certified') {
601
			$sql="SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
602
	         WHERE entity=".$conf->entity." AND certified = 0";
603
604
		}
605
		else if ($element=='just_certified') {
606
			$sql="SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
607
	         WHERE entity=".$conf->entity." AND certified = 1";
608
609
		}
610
		else{
611
			$sql="SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
612
	         WHERE element='".$element."' AND fk_object=".(int) $fk_object;
613
		}
614
615
		if($search_start > 0) $sql.=" AND date_creation >= '".$this->db->idate($search_start)."'";
616
		if($search_end > 0) $sql.=" AND date_creation <= '".$this->db->idate($search_end)."'";
617
618
		$sql.=$this->db->order($sortfield, $sortorder);
619
620
		if($limit > 0 )$sql.=' LIMIT '.$limit;
621
622
		$res = $this->db->query($sql);
623
624
		if($res) {
625
626
			$results=array();
627
628
			while ($obj = $this->db->fetch_object($res)) {
629
630
				if (!isset($cachedlogs[$obj->rowid])) {
631
					$b=new BlockedLog($this->db);
632
					$b->fetch($obj->rowid);
633
634
					$cachedlogs[$obj->rowid] = $b;
635
				}
636
637
				$results[] = $cachedlogs[$obj->rowid];
638
			}
639
640
			return $results;
641
		}
642
		else{
643
			return false;
644
		}
645
	}
646
647
	/**
648
	 *	Return the signature (hash) of the "genesis-block" (Block 0)
649
	 *
650
	 *	@return	string					Signature of genesis-block for current conf->entity
651
	 */
652
	public function getSignature()
653
	{
654
		global $db,$conf,$mysoc;
655
656
		if (empty($conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT)) { // creation of a unique fingerprint
657
658
			require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
659
660
			$fingerprint = dol_hash(print_r($mysoc,true).getRandomPassword(1), '5');
661
662
			dolibarr_set_const($db, 'BLOCKEDLOG_ENTITY_FINGERPRINT', $fingerprint, 'chaine',0,'Numeric Unique Fingerprint', $conf->entity);
663
664
			$conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT=$fingerprint;
665
		}
666
667
		return $conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT;
668
	}
669
670
}
671
672