Completed
Push — 1.2 ( 52818d...320c8c )
by David
12s queued 10s
created

AbstractZohoDao::getById()   A

Complexity

Conditions 5
Paths 24

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 31
rs 9.1128
c 0
b 0
f 0
cc 5
nc 24
nop 1
1
<?php
2
3
namespace Wabel\Zoho\CRM;
4
5
use Psr\Http\Message\UriInterface;
6
use Wabel\Zoho\CRM\Exception\ZohoCRMException;
7
use Wabel\Zoho\CRM\Exception\ZohoCRMResponseException;
8
use Wabel\Zoho\CRM\Exception\ZohoCRMUpdateException;
9
use Wabel\Zoho\CRM\Request\Response;
10
11
/**
12
 * Base class that provides access to Zoho through Zoho beans.
13
 */
14
abstract class AbstractZohoDao
15
{
16
    const ON_DUPLICATE_THROW = 1;
17
    const ON_DUPLICATE_MERGE = 2;
18
    const MAX_GET_RECORDS = 200;
19
    const MAX_GET_RECORDS_BY_ID = 100;
20
    const MAX_SIMULTANEOUS_SAVE = 100;
21
22
    /**
23
     * The class implementing API methods not directly related to a specific module.
24
     *
25
     * @var ZohoClient
26
     */
27
    protected $zohoClient;
28
29
    public function __construct(ZohoClient $zohoClient)
30
    {
31
        $this->zohoClient = $zohoClient;
32
    }
33
34
    abstract protected function getModule();
35
    abstract protected function getSingularModuleName();
36
    abstract protected function getPluralModuleName();
37
    abstract protected function getBeanClassName();
38
    abstract protected function getFields();
39
40
    protected $flatFields;
41
42
    /**
43
     * Returns a flat list of all fields.
44
     *
45
     * @return array The array of field names for a module
46
     */
47
    protected function getFlatFields()
48
    {
49
        if ($this->flatFields === null) {
50
            $this->flatFields = array();
51
            foreach ($this->getFields() as $cat) {
52
                $this->flatFields = array_merge($this->flatFields, $cat);
53
            }
54
        }
55
56
        return $this->flatFields;
57
    }
58
59
    protected $duplicateCheck = self::ON_DUPLICATE_MERGE;
60
61
    public function setDuplicateCheck($duplicateCheck)
62
    {
63
	$this->duplicateCheck = $duplicateCheck;
64
    }
65
66
    protected $wfTrigger = false;
67
68
    public function setWorkflowTrigger($wfTrigger)
69
    {
70
	$this->wfTrigger = $wfTrigger;
71
    }
72
73
    /**
74
     * Parse a Zoho Response in order to retrieve one or several ZohoBeans from it.
75
     *
76
     * @param Response $zohoResponse The response returned by the ZohoClient->call() method
77
     *
78
     * @return ZohoBeanInterface[] The array of Zoho Beans parsed from the response
79
     */
80
    protected function getBeansFromResponse(Response $zohoResponse)
81
    {
82
        $beanClass = $this->getBeanClassName();
83
        $fields = $this->getFlatFields();
84
85
        $beanArray = array();
86
87
        foreach ($zohoResponse->getRecords() as $record) {
88
89
            /** @var ZohoBeanInterface $bean */
90
            $bean = new $beanClass();
91
92
            // First, let's fill the ID.
93
            // The ID is CONTACTID or ACCOUNTID or Id depending on the Zoho type.
94
            $idName = strtoupper(rtrim($this->getModule(), 's'));
95
            if (isset($record[$idName.'ID'])) {
96
                $id = $record[$idName.'ID'];
97
            } elseif (isset($record[$idName.'_ID'])) {
98
                $id = $record[$idName.'_ID'];
99
            } else {
100
                $id = $record['Id'];
101
            }
102
            $bean->setZohoId($id);
103
            $bean->setCreatedTime(\DateTime::createFromFormat('Y-m-d H:i:s', $record['Created Time']));
0 ignored issues
show
Security Bug introduced by
It seems like \DateTime::createFromFor...record['Created Time']) targeting DateTime::createFromFormat() can also be of type false; however, Wabel\Zoho\CRM\ZohoBeanInterface::setCreatedTime() does only seem to accept object<DateTime>, did you maybe forget to handle an error condition?
Loading history...
104
            $bean->setModifiedTime(\DateTime::createFromFormat('Y-m-d H:i:s', $record['Modified Time']));
0 ignored issues
show
Security Bug introduced by
It seems like \DateTime::createFromFor...ecord['Modified Time']) targeting DateTime::createFromFormat() can also be of type false; however, Wabel\Zoho\CRM\ZohoBeanI...face::setModifiedTime() does only seem to accept object<DateTime>, did you maybe forget to handle an error condition?
Loading history...
105
106
            foreach ($record as $key => $value) {
107
                if (isset($fields[$key])) {
108
                    $setter = $fields[$key]['setter'];
109
110
                    switch ($fields[$key]['type']) {
111
                        case 'Date':
112
                            if ($dateObj = \DateTimeImmutable::createFromFormat('M/d/Y', $value)) {
113
                                $value = $dateObj;
114
                            } elseif ($dateObj = \DateTimeImmutable::createFromFormat('Y-m-d', $value)) {
115
                                $value = $dateObj;
116
                            } else {
117
                                throw new ZohoCRMException('Unable to convert the Date field "'.$key."\" into a DateTime PHP object from the the record $id of the module ".$this->getModule().'.');
118
                            }
119
                            break;
120
                        case 'DateTime':
121
                            $value = \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $value);
122
                            break;
123
                        case 'Boolean':
124
                            $value = ($value == 'true');
125
                            break;
126
                        default:
127
                            break;
128
                    }
129
                    $bean->$setter($value);
130
                }
131
            }
132
133
            $beanArray[] = $bean;
134
        }
135
136
        return $beanArray;
137
    }
138
139
    /**
140
     * Convert an array of ZohoBeans into a SimpleXMLElement for use when inserting/updating related records.
141
     *
142
     * @param $zohoBeans ZohoBeanInterface[]
143
     *
144
     * @return \SimpleXMLElement The SimpleXMLElement containing the XML for a request
145
     */
146
    public function toXmlRelatedRecords($zohoBeans)
147
    {
148
    	return $this->toXml($zohoBeans, 1);
149
    }
150
151
    /**
152
     * Convert an array of ZohoBeans into a SimpleXMLElement.
153
     *
154
     * @param $zohoBeans ZohoBeanInterface[]
155
     *
156
     * @return \SimpleXMLElement The SimpleXMLElement containing the XML for a request
157
     */
158
    public function toXml($zohoBeans, $isRelatedRecords = 0)
159
    {
160
        $module = $this->getModule();
161
162
        $no = 1;
163
        $module = new \SimpleXMLElement("<$module/>");
164
165
        foreach ($zohoBeans as $zohoBean) {
166
            if (!$zohoBean instanceof ZohoBeanInterface) {
167
                throw new ZohoCRMException('Zoho beans sent to save must implement the ZohoBeanInterface.');
168
            }
169
170
            $properties = $this->getFlatFields();
171
            $row = $module->addChild('row');
172
            $row->addAttribute('no', $no);
173
174
            $fl = $row->addChild('FL', $zohoBean->getZohoId());
175
            $id = 'Id';
176
            if ($isRelatedRecords) {
177
	            $idName = strtoupper(rtrim($this->getModule(), 's'));
178
	            $id = $idName . 'ID';
179
	        }
180
            $fl->addAttribute('val', $id);
181
182
            foreach ($properties as $name => $params) {
183
                $camelCaseName = $params['name'];
184
                $isDirty = $zohoBean->isDirty($camelCaseName);
185
                if (!$isDirty) {
186
                    continue;
187
                }
188
189
                $getter = $params['getter'];
190
                $value = $zohoBean->$getter();
191
192
                if (!empty($value) || is_bool($value)) {
193
194
                    // We convert the value back to a proper format if the Zoho Type is Date, DateTime or Boolean
195
                    switch ($params['type']) {
196
                        case 'Date':
197
                            /** @var \DateTime $value */
198
                            $value = $value->format('m/d/Y');
199
                            break;
200
                        case 'DateTime':
201
                            /** @var \DateTime $value */
202
                            $value = $value->format('Y-m-d H:i:s');
203
                            break;
204
                        case 'Boolean':
205
                            /** @var bool $value */
206
                            $value = $value ? 'true' : 'false';
207
                            break;
208
                        default:
209
                            break;
210
                    }
211
                }
212
213
                $fl = $row->addChild('FL', htmlspecialchars($value));
214
                $fl->addAttribute('val', $name);
215
            }
216
            ++$no;
217
        }
218
219
        return $module;
220
    }
221
222
    /**
223
     * Implements deleteRecords API method.
224
     *
225
     * @param string $id Zoho Id of the record to delete
226
     *
227
     * @throws ZohoCRMResponseException
228
     */
229
    public function delete($id)
230
    {
231
        $this->zohoClient->deleteRecords($this->getModule(), $id);
232
    }
233
234
    /**
235
     * Implements getRecordById API method.
236
     *
237
     * @param string|array $id Zoho Id of the record to retrieve OR an array of IDs
238
     *
239
     * @return ZohoBeanInterface[] The array of Zoho Beans parsed from the response
240
     *
241
     * @throws ZohoCRMResponseException
242
     */
243
    public function getById($id)
244
    {
245
        try {
246
            $module = $this->getModule();
247
            $beans = [];
248
249
            // If there's several IDs to process, we divide them by pools of 100 and implode them before requesting
250
            if (is_array($id)) {
251
                foreach (array_chunk($id, self::MAX_GET_RECORDS_BY_ID) as $pool) {
252
                    $idlist = implode(';', $pool);
253
                    $response = $this->zohoClient->getRecordById($module, $idlist);
254
                    $beans = array_merge($beans, $this->getBeansFromResponse($response));
255
                }
256
            }
257
            // if not, we simply request our record
258
            else {
259
                $response = $this->zohoClient->getRecordById($module, $id);
260
                $beans = $this->getBeansFromResponse($response);
261
                $beans = array_shift($beans);
262
            }
263
264
            return $beans;
265
        } catch (ZohoCRMResponseException $e) {
266
            // No records found? Let's return an empty array!
267
            if ($e->getCode() == 4422) {
268
                return array();
269
            } else {
270
                throw $e;
271
            }
272
        }
273
    }
274
275
    /**
276
     * Implements getRecords API method.
277
     *
278
     * @param $sortColumnString
279
     * @param $sortOrderString
280
     * @param \DateTime $lastModifiedTime
281
     * @param $selectColumns
282
     * @param $limit
283
     *
284
     * @return ZohoBeanInterface[] The array of Zoho Beans parsed from the response
285
     *
286
     * @throws ZohoCRMResponseException
287
     */
288 View Code Duplication
    public function getRecords($sortColumnString = null, $sortOrderString = null, \DateTime $lastModifiedTime = null, $selectColumns = null, $limit = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
289
    {
290
        $globalResponse = array();
291
292
        do {
293
            try {
294
                $fromIndex = count($globalResponse) + 1;
295
                $toIndex = $fromIndex + self::MAX_GET_RECORDS - 1;
296
297
                if ($limit) {
298
                    $toIndex = min($limit, $toIndex);
299
                }
300
301
                $response = $this->zohoClient->getRecords($this->getModule(), $sortColumnString, $sortOrderString, $lastModifiedTime, $selectColumns, $fromIndex, $toIndex);
302
                $beans = $this->getBeansFromResponse($response);
303
            } catch (ZohoCRMResponseException $e) {
304
                // No records found? Let's return an empty array!
305
                if ($e->getCode() == 4422) {
306
                    $beans = array();
307
                } else {
308
                    throw $e;
309
                }
310
            }
311
312
            $globalResponse = array_merge($globalResponse, $beans);
313
        } while (count($beans) == self::MAX_GET_RECORDS);
314
315
        return $globalResponse;
316
    }
317
318
    /**
319
     * Returns the list of deleted records.
320
     *
321
     * @param \DateTimeInterface|null $lastModifiedTime
322
     * @param int                     $limit
323
     *
324
     * @return array
325
     *
326
     * @throws ZohoCRMResponseException
327
     * @throws \Exception
328
     */
329 View Code Duplication
    public function getDeletedRecordIds(\DateTimeInterface $lastModifiedTime = null, $limit = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
330
    {
331
        $globalDeletedIDs = array();
332
333
        do {
334
            try {
335
                $fromIndex = count($globalDeletedIDs) + 1;
336
                $toIndex = $fromIndex + self::MAX_GET_RECORDS - 1;
337
338
                if ($limit) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $limit of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
339
                    $toIndex = min($limit - 1, $toIndex);
340
                }
341
342
                $response = $this->zohoClient->getDeletedRecordIds($this->getModule(), $lastModifiedTime, $fromIndex, $toIndex);
343
                $deletedIDs = $response->getDeletedIds();
344
            } catch (ZohoCRMResponseException $e) {
345
                // No records found? Let's return an empty array!
346
                if ($e->getZohoCode() == 4422) {
347
                    $deletedIDs = array();
348
                } else {
349
                    throw $e;
350
                }
351
            }
352
353
            $globalDeletedIDs = array_merge($globalDeletedIDs, $deletedIDs);
354
        } while (count($deletedIDs) == self::MAX_GET_RECORDS);
355
356
        return $globalDeletedIDs;
357
    }
358
359
    /**
360
     * Implements getRecords API method.
361
     *
362
     * @param string $id           Zoho Id of the record to delete
363
     * @param string $parentModule The parent module of the records
364
     * @param int    $limit        The max number of records to fetch
365
     *
366
     * @return ZohoBeanInterface[] The array of Zoho Beans parsed from the response
367
     *
368
     * @throws ZohoCRMResponseException
369
     */
370 View Code Duplication
    public function getRelatedRecords($id, $parentModule, $limit = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
371
    {
372
        $globalResponse = array();
373
374
        do {
375
            try {
376
                $fromIndex = count($globalResponse) + 1;
377
                $toIndex = $fromIndex + self::MAX_GET_RECORDS - 1;
378
379
                if ($limit) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $limit of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
380
                    $toIndex = min($limit - 1, $toIndex);
381
                }
382
383
                $response = $this->zohoClient->getRelatedRecords($this->getModule(), $id, $parentModule, $fromIndex, $toIndex);
384
                $beans = $this->getBeansFromResponse($response);
385
            } catch (ZohoCRMResponseException $e) {
386
                // No records found? Let's return an empty array!
387
                if ($e->getCode() == 4422) {
388
                    $beans = array();
389
                } else {
390
                    throw $e;
391
                }
392
            }
393
394
            $globalResponse = array_merge($globalResponse, $beans);
395
        } while (count($beans) == self::MAX_GET_RECORDS);
396
397
        return $globalResponse;
398
    }
399
400
    /**
401
     * Implements searchRecords API method.
402
     *
403
     * @param string    $searchCondition  The search criteria formatted like
404
     * @param int       $limit            The maximum number of beans returned from Zoho
405
     * @param \DateTime $lastModifiedTime
406
     * @param string    $selectColumns    The list
407
     *
408
     * @return ZohoBeanInterface[] The array of Zoho Beans parsed from the response
409
     *
410
     * @throws ZohoCRMResponseException
411
     */
412 View Code Duplication
    public function searchRecords($searchCondition = null, $limit = null, \DateTime $lastModifiedTime = null, $selectColumns = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
413
    {
414
        $globalResponse = array();
415
416
        do {
417
            try {
418
                $fromIndex = count($globalResponse) + 1;
419
                $toIndex = $fromIndex + self::MAX_GET_RECORDS - 1;
420
421
                if ($limit) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $limit of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
422
                    $toIndex = min($limit - 1, $toIndex);
423
                }
424
425
                $response = $this->zohoClient->searchRecords($this->getModule(), $searchCondition, $fromIndex, $toIndex, $lastModifiedTime, $selectColumns);
0 ignored issues
show
Bug introduced by
It seems like $selectColumns defined by parameter $selectColumns on line 412 can also be of type string; however, Wabel\Zoho\CRM\ZohoClient::searchRecords() does only seem to accept null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
426
                $beans = $this->getBeansFromResponse($response);
427
            } catch (ZohoCRMResponseException $e) {
428
                // No records found? Let's return an empty array!
429
                if ($e->getCode() == 4422) {
430
                    $beans = array();
431
                } else {
432
                    throw $e;
433
                }
434
            }
435
436
            $globalResponse = array_merge($globalResponse, $beans);
437
        } while (count($beans) == self::MAX_GET_RECORDS);
438
439
        return $globalResponse;
440
    }
441
442
    /**
443
     * Implements insertRecords API method.
444
     *
445
     * WARNING : When setting wfTrigger to true, this method will use an API call per bean
446
     * passed in argument. This is caused by Zoho limitation which forbids triggering any
447
     * workflow when inserting several beans simultaneously.
448
     *
449
     * @param ZohoBeanInterface[] $beans          The Zoho Beans to insert in the CRM
450
     * @param bool                $wfTrigger      Whether or not the call should trigger the workflows related to a "created" event
451
     * @param int                 $duplicateCheck 1 : Throwing error when a duplicate is found; 2 : Merging with existing duplicate
452
     * @param bool                $isApproval     Whether or not to push the record into an approval sandbox first
453
     *
454
     * @throws ZohoCRMResponseException
455
     */
456
    public function insertRecords($beans, $wfTrigger = null, $duplicateCheck = null, $isApproval = null)
457
    {
458
        $records = [];
459
460
	// For duplicate check and wfTrigger, use the setting passed or the object-wide setting
461
	$duplicateCheck = $duplicateCheck ?: $this->duplicateCheck;
462
	$wfTrigger = ($wfTrigger === null ? $this->wfTrigger : $wfTrigger);
463
464
        if ($wfTrigger) {
465
            // If we trigger workflows, we trigger the insert of beans one by one.
466
            foreach ($beans as $bean) {
467
                $xmlData = $this->toXml([$bean]);
468
                $response = $this->zohoClient->insertRecords($this->getModule(), $xmlData, $wfTrigger, $duplicateCheck, $isApproval);
469
                $records = array_merge($records, $response->getRecords());
470
            }
471 View Code Duplication
        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
472
            // We can't pass more than 100 records to Zoho, so we split the request into pieces of 100
473
            foreach (array_chunk($beans, 100) as $beanPool) {
474
                $xmlData = $this->toXml($beanPool);
475
                $response = $this->zohoClient->insertRecords($this->getModule(), $xmlData, $wfTrigger, $duplicateCheck, $isApproval);
476
                $records = array_merge($records, $response->getRecords());
477
            }
478
        }
479 View Code Duplication
        if (count($records) != count($beans)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
480
            throw new ZohoCRMException('Error while inserting beans in Zoho. '.count($beans).' passed in parameter, but '.count($records).' returned.');
481
        }
482
483
        foreach ($beans as $key => $bean) {
484
            $record = $records[$key];
485
486
            if ($wfTrigger && (!isset($record['Id']) || empty($record['Id']))) {
487
                // This field is probably in error!
488
                throw new ZohoCRMException('An error occurred while inserting records and triggering workflow: '.$record['message'], $record['code']);
489
            } elseif (!$wfTrigger && substr($record['code'], 0, 1) != '2') {
490
                // This field is probably in error!
491
                throw new ZohoCRMException('An error occurred while inserting records: '.$record['message'], $record['code']);
492
            }
493
494
            $bean->setZohoId($record['Id']);
495
            $bean->setCreatedTime(\DateTime::createFromFormat('Y-m-d H:i:s', $record['Created Time']));
0 ignored issues
show
Security Bug introduced by
It seems like \DateTime::createFromFor...record['Created Time']) targeting DateTime::createFromFormat() can also be of type false; however, Wabel\Zoho\CRM\ZohoBeanInterface::setCreatedTime() does only seem to accept object<DateTime>, did you maybe forget to handle an error condition?
Loading history...
496
            if ($record['Modified Time']) {
497
                $bean->setModifiedTime(\DateTime::createFromFormat('Y-m-d H:i:s', $record['Modified Time']));
0 ignored issues
show
Security Bug introduced by
It seems like \DateTime::createFromFor...ecord['Modified Time']) targeting DateTime::createFromFormat() can also be of type false; however, Wabel\Zoho\CRM\ZohoBeanI...face::setModifiedTime() does only seem to accept object<DateTime>, did you maybe forget to handle an error condition?
Loading history...
498
            }
499
        }
500
    }
501
502
    /**
503
     * Implements updateRecords API method.
504
     *
505
     * @param array $beans     The list of beans to update.
506
     * @param bool  $wfTrigger Set value as true to trigger the workflow rule in Zoho
507
     *
508
     * @return Response The Response object
509
     *
510
     * @throws ZohoCRMException
511
     */
512
    public function updateRecords(array $beans, $wfTrigger = null)
513
    {
514
        $records = [];
515
516
	$wfTrigger = ($wfTrigger === null ? $this->wfTrigger : $wfTrigger);
517
	
518
        if ($wfTrigger) {
519
            // If we trigger workflows, we trigger the insert of beans one by one.
520
            foreach ($beans as $bean) {
521
                $xmlData = $this->toXml([$bean]);
522
                $response = $this->zohoClient->updateRecords($this->getModule(), $xmlData, $bean->getZohoId(), $wfTrigger);
523
                $records = array_merge($records, $response->getRecords());
524
            }
525 View Code Duplication
        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
526
            // We can't pass more than 100 records to Zoho, so we split the request into pieces of 100
527
            foreach (array_chunk($beans, 100) as $beanPool) {
528
                $xmlData = $this->toXml($beanPool);
529
                $response = $this->zohoClient->updateRecords($this->getModule(), $xmlData, null, $wfTrigger);
530
                $records = array_merge($records, $response->getRecords());
531
            }
532
        }
533 View Code Duplication
        if (count($records) != count($beans)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
534
            throw new ZohoCRMException('Error while inserting beans in Zoho. '.count($beans).' passed in parameter, but '.count($records).' returned.');
535
        }
536
537
        $exceptions = new \SplObjectStorage();
538
539
        foreach ($beans as $key => $bean) {
540
            $record = $records[$key];
541
542
            if ($wfTrigger && (!isset($record['Id']) || empty($record['Id']))) {
543
                // This field is probably in error!
544
                throw new ZohoCRMException('An error occurred while updating records and triggering workflow: '.$record['message'], $record['code']);
545
            } elseif (!$wfTrigger && substr($record['code'], 0, 1) != '2') {
546
                // This field is probably in error!
547
                $exceptions->attach($bean, new ZohoCRMException('An error occurred while updating records. '.(isset($record['message']) ? $record['message'] : ''), $record['code']));
548
                continue;
549
            }
550
551
            if ($record['Id'] != $bean->getZohoId()) {
552
                // This field is probably in error!
553
                $exceptions->attach($bean, new ZohoCRMException('An error occurred while updating records. The Zoho ID to update was '.$bean->getZohoId().', returned '.$record['Id']));
554
                continue;
555
            }
556
557
            if ($record['Modified Time']) {
558
                $bean->setModifiedTime(\DateTime::createFromFormat('Y-m-d H:i:s', $record['Modified Time']));
559
            }
560
        }
561
        if ($exceptions->count() != 0) {
562
            throw new ZohoCRMUpdateException($exceptions);
563
        }
564
    }
565
566
    /**
567
     * Implements uploadFile API method.
568
     *
569
     * @param string $id      Zoho Id of the record to retrieve
570
     * @param string|\SplFileInfo|resource|UriInterface $content Can be either the content to upload, a file information, a file handle, or the Uri of a remote file.
571
     * @param string $filename The name (optional) under which the file will be stored by Zoho CRM. Mandatory if posting content as string.
572
     *
573
     * @return Response The Response object
574
     *
575
     * @throws ZohoCRMResponseException
576
     */
577
    public function uploadFile($id, $content, $filename = null)
578
    {
579
        return $this->zohoClient->uploadFile($this->getModule(), $id, $content, $filename);
580
    }
581
582
    /**
583
     * Implements downloadFile API method.
584
     *
585
     * @param string $id unique ID of the attachment
586
     *
587
     * @return Response The Response object
588
     */
589
    public function downloadFile($id)
590
    {
591
        return $this->zohoClient->downloadFile($this->getModule(), $id);
592
    }
593
594
    /**
595
     * Saves the bean or array of beans passed in Zoho.
596
     * It will perform an insert if the bean has no ZohoID or an update if the bean has a ZohoID.
597
     *
598
     * @param array|object $beans A bean or an array of beans.
599
     *
600
     * TODO: isApproval is not used by each module.
601
     * TODO: wfTrigger only usable for a single record update/insert.
602
     */
603
    public function save($beans, $wfTrigger = null, $duplicateCheck = null, $isApproval = false)
604
    {
605
	// For duplicate check and wfTrigger, use the setting passed or the object-wide setting
606
	$duplicateCheck = $duplicateCheck ?: $this->duplicateCheck;
607
	$wfTrigger = ($wfTrigger === null ? $this->wfTrigger : $wfTrigger);
608
	
609
        if (!is_array($beans)) {
610
            $beans = [$beans];
611
        }
612
613
        $toInsert = [];
614
        $toUpdate = [];
615
616
        foreach ($beans as $bean) {
617
            if ($bean->getZohoId()) {
618
                $toUpdate[] = $bean;
619
            } else {
620
                $toInsert[] = $bean;
621
            }
622
        }
623
624
        if ($toInsert) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $toInsert of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
625
            $this->insertRecords($toInsert, $wfTrigger, $duplicateCheck, $isApproval);
626
        }
627
        if ($toUpdate) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $toUpdate of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
628
            $this->updateRecords($toUpdate, $wfTrigger);
629
        }
630
    }
631
}
632