Passed
Push — main ( f1540e...02d90d )
by Rafael
45:15
created

Contacts   F

Complexity

Total Complexity 97

Size/Duplication

Total Lines 575
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 224
dl 0
loc 575
rs 2
c 0
b 0
f 0
wmc 97

13 Methods

Rating   Name   Duplication   Size   Complexity  
B getByEmail() 0 33 8
B get() 0 33 8
A addCategory() 0 26 6
A deleteCategory() 0 26 6
A _cleanObjectDatas() 0 16 1
A _validate() 0 11 3
C put() 0 43 14
B post() 0 30 11
A __construct() 0 7 1
A delete() 0 15 4
B createUser() 0 42 8
F index() 0 95 24
A getCategories() 0 15 3

How to fix   Complexity   

Complex Class

Complex classes like Contacts often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Contacts, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/* Copyright (C) 2015       Jean-François Ferry         <[email protected]>
4
 * Copyright (C) 2019       Frédéric France             <[email protected]>
5
 * Copyright (C) 2024		MDW						<[email protected]>
6
 * Copyright (C) 2024       Rafael San José         <[email protected]>
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
use DoliCore\Api\DolibarrApi;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, DolibarrApi. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
23
use Luracast\Restler\RestException;
24
25
//require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
26
//require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
27
28
29
/**
30
 * API class for contacts
31
 *
32
 * @access protected
33
 * @class  DolibarrApiAccess {@requires user,external}
34
 */
35
class Contacts extends DolibarrApi
36
{
37
    /**
38
     *
39
     * @var array $FIELDS Mandatory fields, checked when create and update object
40
     */
41
    public static $FIELDS = [
42
        'lastname',
43
    ];
44
45
    /**
46
     * @var Contact $contact {@type Contact}
47
     */
48
    public $contact;
49
50
    /**
51
     * Constructor
52
     */
53
    public function __construct()
54
    {
55
        global $db, $conf;
56
        $this->db = $db;
57
58
59
        $this->contact = new Contact($this->db);
60
    }
61
62
    /**
63
     * Get properties of a contact object by Email
64
     *
65
     * @param string $email        Email of contact
66
     * @param int    $includecount Count and return also number of elements the contact is used as a link for
67
     * @param int    $includeroles Includes roles of the contact
68
     *
69
     * @return  array|mixed data without useless information
70
     *
71
     * @url GET email/{email}
72
     *
73
     * @throws RestException 401     Insufficient rights
74
     * @throws RestException 404     User or group not found
75
     */
76
    public function getByEmail($email, $includecount = 0, $includeroles = 0)
77
    {
78
        if (!DolibarrApiAccess::$user->hasRight('societe', 'contact', 'lire')) {
79
            throw new RestException(401, 'No permission to read contacts');
80
        }
81
82
        if (empty($email)) {
83
            $result = $this->contact->initAsSpecimen();
84
        } else {
85
            $result = $this->contact->fetch('', '', '', $email);
86
        }
87
88
        if (!$result) {
89
            throw new RestException(404, 'Contact not found');
90
        }
91
92
        if (!DolibarrApi::_checkAccessToResource('contact', $this->contact->id, 'socpeople&societe')) {
93
            throw new RestException(401, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
94
        }
95
96
        if ($includecount) {
97
            $this->contact->load_ref_elements();
98
        }
99
100
        if ($includeroles) {
101
            $this->contact->fetchRoles();
102
        }
103
104
        if (isModEnabled('mailing')) {
105
            $this->contact->getNoEmail();
106
        }
107
108
        return $this->_cleanObjectDatas($this->contact);
109
    }
110
111
    /**
112
     * Clean sensible object datas
113
     *
114
     * @param Object $object Object to clean
115
     *
116
     * @return  Object              Object with cleaned properties
117
     */
118
    protected function _cleanObjectDatas($object)
119
    {
120
        // phpcs:enable
121
        $object = parent::_cleanObjectDatas($object);
122
123
        unset($object->total_ht);
124
        unset($object->total_tva);
125
        unset($object->total_localtax1);
126
        unset($object->total_localtax2);
127
        unset($object->total_ttc);
128
129
        unset($object->note);
130
        unset($object->lines);
131
        unset($object->thirdparty);
132
133
        return $object;
134
    }
135
136
    /**
137
     * List contacts
138
     *
139
     * Get a list of contacts
140
     *
141
     * @param string $sortfield      Sort field
142
     * @param string $sortorder      Sort order
143
     * @param int    $limit          Limit for list
144
     * @param int    $page           Page number
145
     * @param string $thirdparty_ids Thirdparty ids to filter contacts of (example '1' or '1,2,3')
146
     *                               {@pattern /^[0-9,]*$/i}
147
     * @param int    $category       Use this param to filter list by category
148
     * @param string $sqlfilters     Other criteria to filter answers separated by a comma. Syntax example
149
     *                               "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
150
     * @param int    $includecount   Count and return also number of elements the contact is used as a link for
151
     * @param int    $includeroles   Includes roles of the contact
152
     * @param string $properties     Restrict the data returned to these properties. Ignored if empty. Comma separated
153
     *                               list of properties names
154
     *
155
     * @return Contact[]                        Array of contact objects
156
     *
157
     * @throws RestException
158
     */
159
    public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $category = 0, $sqlfilters = '', $includecount = 0, $includeroles = 0, $properties = '')
160
    {
161
        global $db, $conf;
162
163
        $obj_ret = [];
164
165
        if (!DolibarrApiAccess::$user->hasRight('societe', 'contact', 'lire')) {
166
            throw new RestException(401, 'No permission to read contacts');
167
        }
168
169
        // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
170
        $socids = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : $thirdparty_ids;
171
172
        // If the internal user must only see his customers, force searching by him
173
        $search_sale = 0;
174
        if (!DolibarrApiAccess::$user->hasRight('societe', 'client', 'voir') && !$socids) {
175
            $search_sale = DolibarrApiAccess::$user->id;
176
        }
177
178
        $sql = "SELECT t.rowid";
179
        $sql .= " FROM " . MAIN_DB_PREFIX . "socpeople as t";
180
        if ($category > 0) {
181
            $sql .= ", " . MAIN_DB_PREFIX . "categorie_contact as c";
182
        }
183
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "socpeople_extrafields as te ON te.fk_object = t.rowid";
184
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s ON t.fk_soc = s.rowid";
185
        $sql .= ' WHERE t.entity IN (' . getEntity('contact') . ')';
186
        if ($socids) {
187
            $sql .= " AND t.fk_soc IN (" . $this->db->sanitize($socids) . ")";
188
        }
189
        // Search on sale representative
190
        if ($search_sale && $search_sale != '-1') {
191
            if ($search_sale == -2) {
192
                $sql .= " AND NOT EXISTS (SELECT sc.fk_soc FROM " . MAIN_DB_PREFIX . "societe_commerciaux as sc WHERE sc.fk_soc = t.fk_soc)";
193
            } elseif ($search_sale > 0) {
194
                $sql .= " AND EXISTS (SELECT sc.fk_soc FROM " . MAIN_DB_PREFIX . "societe_commerciaux as sc WHERE sc.fk_soc = t.fk_soc AND sc.fk_user = " . ((int) $search_sale) . ")";
195
            }
196
        }
197
        // Select contacts of given category
198
        if ($category > 0) {
199
            $sql .= " AND c.fk_categorie = " . ((int) $category);
200
            $sql .= " AND c.fk_socpeople = t.rowid ";
201
        }
202
203
        // Add sql filters
204
        if ($sqlfilters) {
205
            $errormessage = '';
206
            $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
207
            if ($errormessage) {
208
                throw new RestException(400, 'Error when validating parameter sqlfilters -> ' . $errormessage);
209
            }
210
        }
211
212
        $sql .= $this->db->order($sortfield, $sortorder);
213
214
        if ($limit) {
215
            if ($page < 0) {
216
                $page = 0;
217
            }
218
            $offset = $limit * $page;
219
220
            $sql .= $this->db->plimit($limit + 1, $offset);
221
        }
222
        $result = $this->db->query($sql);
223
        if ($result) {
224
            $num = $this->db->num_rows($result);
225
            $min = min($num, ($limit <= 0 ? $num : $limit));
226
            $i = 0;
227
            while ($i < $min) {
228
                $obj = $this->db->fetch_object($result);
229
                $contact_static = new Contact($this->db);
230
                if ($contact_static->fetch($obj->rowid)) {
231
                    $contact_static->fetchRoles();
232
                    if ($includecount) {
233
                        $contact_static->load_ref_elements();
234
                    }
235
                    if ($includeroles) {
236
                        $contact_static->fetchRoles();
237
                    }
238
                    if (isModEnabled('mailing')) {
239
                        $contact_static->getNoEmail();
240
                    }
241
242
                    $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($contact_static), $properties);
243
                }
244
245
                $i++;
246
            }
247
        } else {
248
            throw new RestException(503, 'Error when retrieve contacts : ' . $sql);
249
        }
250
        if (!count($obj_ret)) {
251
            throw new RestException(404, 'Contacts not found');
252
        }
253
        return $obj_ret;
254
    }
255
256
    /**
257
     * Create contact object
258
     *
259
     * @param array $request_data Request datas
260
     *
261
     * @return  int     ID of contact
262
     *
263
     * @suppress PhanPluginUnknownArrayMethodParamType  Luracast limitation
264
     */
265
    public function post($request_data = null)
266
    {
267
        if (!DolibarrApiAccess::$user->hasRight('societe', 'contact', 'creer')) {
268
            throw new RestException(401, 'No permission to create/update contacts');
269
        }
270
        // Check mandatory fields
271
        $result = $this->_validate($request_data);
272
273
        foreach ($request_data as $field => $value) {
274
            if ($field === 'caller') {
275
                // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller
276
                $this->contact->context['caller'] = $request_data['caller'];
277
                continue;
278
            }
279
            if ($field == 'array_options' && is_array($value)) {
280
                foreach ($value as $index => $val) {
281
                    $this->contact->array_options[$index] = $val;
282
                }
283
                continue;
284
            }
285
286
            $this->contact->$field = $this->_checkValForAPI($field, $value, $this->contact);
287
        }
288
        if ($this->contact->create(DolibarrApiAccess::$user) < 0) {
289
            throw new RestException(500, "Error creating contact", array_merge([$this->contact->error], $this->contact->errors));
290
        }
291
        if (isModEnabled('mailing') && !empty($this->contact->email) && isset($this->contact->no_email)) {
292
            $this->contact->setNoEmail($this->contact->no_email);
293
        }
294
        return $this->contact->id;
295
    }
296
297
    /**
298
     * Validate fields before create or update object
299
     *
300
     * @param string[]|null $data Data to validate
301
     *
302
     * @return  string[]
303
     * @throws  RestException
304
     */
305
    private function _validate($data)
306
    {
307
        $contact = [];
308
        foreach (Contacts::$FIELDS as $field) {
309
            if (!isset($data[$field])) {
310
                throw new RestException(400, "$field field missing");
311
            }
312
            $contact[$field] = $data[$field];
313
        }
314
315
        return $contact;
316
    }
317
318
    /**
319
     * Update contact
320
     *
321
     * @param int   $id           Id of contact to update
322
     * @param array $request_data Datas
323
     *
324
     * @return  Object|false                Updated object, false when issue toupdate
325
     */
326
    public function put($id, $request_data = null)
327
    {
328
        if (!DolibarrApiAccess::$user->hasRight('societe', 'contact', 'creer')) {
329
            throw new RestException(401, 'No permission to create/update contacts');
330
        }
331
332
        $result = $this->contact->fetch($id);
333
        if (!$result) {
334
            throw new RestException(404, 'Contact not found');
335
        }
336
337
        if (!DolibarrApi::_checkAccessToResource('contact', $this->contact->id, 'socpeople&societe')) {
338
            throw new RestException(401, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
339
        }
340
341
        foreach ($request_data as $field => $value) {
342
            if ($field == 'id') {
343
                continue;
344
            }
345
            if ($field === 'caller') {
346
                // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller
347
                $this->contact->context['caller'] = $request_data['caller'];
348
                continue;
349
            }
350
            if ($field == 'array_options' && is_array($value)) {
351
                foreach ($value as $index => $val) {
352
                    $this->contact->array_options[$index] = $val;
353
                }
354
                continue;
355
            }
356
357
            $this->contact->$field = $this->_checkValForAPI($field, $value, $this->contact);
358
        }
359
360
        if (isModEnabled('mailing') && !empty($this->contact->email) && isset($this->contact->no_email)) {
361
            $this->contact->setNoEmail($this->contact->no_email);
362
        }
363
364
        if ($this->contact->update($id, DolibarrApiAccess::$user, 1, 'update')) {
365
            return $this->get($id);
366
        }
367
368
        return false;
369
    }
370
371
    /**
372
     * Get properties of a contact object
373
     *
374
     * Return an array with contact information
375
     *
376
     * @param int $id           ID of contact
377
     * @param int $includecount Count and return also number of elements the contact is used as a link for
378
     * @param int $includeroles Includes roles of the contact
379
     *
380
     * @return  array|mixed data without useless information
381
     *
382
     * @throws  RestException
383
     */
384
    public function get($id, $includecount = 0, $includeroles = 0)
385
    {
386
        if (!DolibarrApiAccess::$user->hasRight('societe', 'contact', 'lire')) {
387
            throw new RestException(401, 'No permission to read contacts');
388
        }
389
390
        if ($id === 0) {
391
            $result = $this->contact->initAsSpecimen();
392
        } else {
393
            $result = $this->contact->fetch($id);
394
        }
395
396
        if (!$result) {
397
            throw new RestException(404, 'Contact not found');
398
        }
399
400
        if (!DolibarrApi::_checkAccessToResource('contact', $this->contact->id, 'socpeople&societe')) {
401
            throw new RestException(401, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
402
        }
403
404
        if ($includecount) {
405
            $this->contact->load_ref_elements();
406
        }
407
408
        if ($includeroles) {
409
            $this->contact->fetchRoles();
410
        }
411
412
        if (isModEnabled('mailing')) {
413
            $this->contact->getNoEmail();
414
        }
415
416
        return $this->_cleanObjectDatas($this->contact);
417
    }
418
419
    /**
420
     * Delete contact
421
     *
422
     * @param int $id Contact ID
423
     *
424
     * @return  integer
425
     */
426
    public function delete($id)
427
    {
428
        if (!DolibarrApiAccess::$user->hasRight('societe', 'contact', 'supprimer')) {
429
            throw new RestException(401, 'No permission to delete contacts');
430
        }
431
        $result = $this->contact->fetch($id);
432
        if (!$result) {
433
            throw new RestException(404, 'Contact not found');
434
        }
435
436
        if (!DolibarrApi::_checkAccessToResource('contact', $this->contact->id, 'socpeople&societe')) {
437
            throw new RestException(401, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
438
        }
439
        $this->contact->oldcopy = clone $this->contact;
440
        return $this->contact->delete(DolibarrApiAccess::$user);
441
    }
442
443
    /**
444
     * Create an user account object from contact (external user)
445
     *
446
     * @param int   $id           Id of contact
447
     * @param array $request_data Request datas
448
     *
449
     * @return  int     ID of user
450
     *
451
     * @url      POST {id}/createUser
452
     * @suppress PhanPluginUnknownArrayMethodParamType  Luracast limitation
453
     */
454
    public function createUser($id, $request_data = null)
455
    {
456
        //if (!DolibarrApiAccess::$user->hasRight('user', 'user', 'creer')) {
457
        //throw new RestException(403);
458
        //}
459
460
        if (!isset($request_data["login"])) {
461
            throw new RestException(400, "login field missing");
462
        }
463
        if (!isset($request_data["password"])) {
464
            throw new RestException(400, "password field missing");
465
        }
466
467
        if (!DolibarrApiAccess::$user->hasRight('societe', 'contact', 'lire')) {
468
            throw new RestException(403, 'No permission to read contacts');
469
        }
470
        if (!DolibarrApiAccess::$user->hasRight('user', 'user', 'creer')) {
471
            throw new RestException(403, 'No permission to create user');
472
        }
473
474
        $contact = new Contact($this->db);
475
        $contact->fetch($id);
476
        if ($contact->id <= 0) {
477
            throw new RestException(404, 'Contact not found');
478
        }
479
480
        if (!DolibarrApi::_checkAccessToResource('contact', $contact->id, 'socpeople&societe')) {
481
            throw new RestException(403, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
482
        }
483
484
        // Check mandatory fields
485
        $login = $request_data["login"];
486
        $password = $request_data["password"];
487
        $useraccount = new User($this->db);
488
        $result = $useraccount->create_from_contact($contact, $login, $password);
489
        if ($result <= 0) {
490
            throw new RestException(500, "User not created");
491
        }
492
        // password parameter not used in create_from_contact
493
        $useraccount->setPassword($useraccount, $password);
494
495
        return $result;
496
    }
497
498
    /**
499
     * Get categories for a contact
500
     *
501
     * @param int    $id        ID of contact
502
     * @param string $sortfield Sort field
503
     * @param string $sortorder Sort order
504
     * @param int    $limit     Limit for list
505
     * @param int    $page      Page number
506
     *
507
     * @return mixed
508
     *
509
     * @url GET {id}/categories
510
     */
511
    public function getCategories($id, $sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0)
512
    {
513
        if (!DolibarrApiAccess::$user->hasRight('categorie', 'lire')) {
514
            throw new RestException(403);
515
        }
516
517
        $categories = new Categorie($this->db);
518
519
        $result = $categories->getListForItem($id, 'contact', $sortfield, $sortorder, $limit, $page);
520
521
        if ($result < 0) {
522
            throw new RestException(503, 'Error when retrieve category list : ' . $categories->error);
523
        }
524
525
        return $result;
526
    }
527
528
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
529
530
    /**
531
     * Add a category to a contact
532
     *
533
     * @url PUT {id}/categories/{category_id}
534
     *
535
     * @param int $id          Id of contact
536
     * @param int $category_id Id of category
537
     *
538
     * @return  mixed
539
     *
540
     * @throws RestException 401 Insufficient rights
541
     * @throws RestException 404 Category or contact not found
542
     */
543
    public function addCategory($id, $category_id)
544
    {
545
        if (!DolibarrApiAccess::$user->hasRight('societe', 'contact', 'creer')) {
546
            throw new RestException(401, 'Insufficient rights');
547
        }
548
549
        $result = $this->contact->fetch($id);
550
        if (!$result) {
551
            throw new RestException(404, 'Contact not found');
552
        }
553
        $category = new Categorie($this->db);
554
        $result = $category->fetch($category_id);
555
        if (!$result) {
556
            throw new RestException(404, 'category not found');
557
        }
558
559
        if (!DolibarrApi::_checkAccessToResource('contact', $this->contact->id)) {
560
            throw new RestException(401, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
561
        }
562
        if (!DolibarrApi::_checkAccessToResource('category', $category->id)) {
563
            throw new RestException(401, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
564
        }
565
566
        $category->add_type($this->contact, 'contact');
567
568
        return $this->_cleanObjectDatas($this->contact);
569
    }
570
571
    /**
572
     * Remove the link between a category and a contact
573
     *
574
     * @url DELETE {id}/categories/{category_id}
575
     *
576
     * @param int $id          Id of contact
577
     * @param int $category_id Id of category
578
     *
579
     * @return  mixed
580
     *
581
     * @throws  RestException 401     Insufficient rights
582
     * @throws  RestException 404     Category or contact not found
583
     */
584
    public function deleteCategory($id, $category_id)
585
    {
586
        if (!DolibarrApiAccess::$user->hasRight('societe', 'contact', 'creer')) {
587
            throw new RestException(401, 'Insufficient rights');
588
        }
589
590
        $result = $this->contact->fetch($id);
591
        if (!$result) {
592
            throw new RestException(404, 'Contact not found');
593
        }
594
        $category = new Categorie($this->db);
595
        $result = $category->fetch($category_id);
596
        if (!$result) {
597
            throw new RestException(404, 'category not found');
598
        }
599
600
        if (!DolibarrApi::_checkAccessToResource('contact', $this->contact->id)) {
601
            throw new RestException(401, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
602
        }
603
        if (!DolibarrApi::_checkAccessToResource('category', $category->id)) {
604
            throw new RestException(401, 'Access not allowed for login ' . DolibarrApiAccess::$user->login);
605
        }
606
607
        $category->del_type($this->contact, 'contact');
608
609
        return $this->_cleanObjectDatas($this->contact);
610
    }
611
}
612