Completed
Pull Request — 1.1 (#29)
by
unknown
10:22
created

AbstractZohoDao::toXmlRelatedRecords()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Wabel\Zoho\CRM;
4
5
use Wabel\Zoho\CRM\Exception\ZohoCRMException;
6
use Wabel\Zoho\CRM\Exception\ZohoCRMResponseException;
7
use Wabel\Zoho\CRM\Exception\ZohoCRMUpdateException;
8
use Wabel\Zoho\CRM\Request\Response;
9
10
/**
11
 * Base class that provides access to Zoho through Zoho beans.
12
 */
13
abstract class AbstractZohoDao
14
{
15
    const ON_DUPLICATE_THROW = 1;
16
    const ON_DUPLICATE_MERGE = 2;
17
    const MAX_GET_RECORDS = 200;
18
    const MAX_GET_RECORDS_BY_ID = 100;
19
    const MAX_SIMULTANEOUS_SAVE = 100;
20
21
    /**
22
     * The class implementing API methods not directly related to a specific module.
23
     *
24
     * @var ZohoClient
25
     */
26
    protected $zohoClient;
27
28
    public function __construct(ZohoClient $zohoClient)
29
    {
30
        $this->zohoClient = $zohoClient;
31
    }
32
33
    abstract protected function getModule();
34
    abstract protected function getSingularModuleName();
35
    abstract protected function getPluralModuleName();
36
    abstract protected function getBeanClassName();
37
    abstract protected function getFields();
38
39
    protected $flatFields;
40
41
    /**
42
     * Returns a flat list of all fields.
43
     *
44
     * @return array The array of field names for a module
45
     */
46
    protected function getFlatFields()
47
    {
48
        if ($this->flatFields === null) {
49
            $this->flatFields = array();
50
            foreach ($this->getFields() as $cat) {
51
                $this->flatFields = array_merge($this->flatFields, $cat);
52
            }
53
        }
54
55
        return $this->flatFields;
56
    }
57
58
    protected $duplicateCheck = self::ON_DUPLICATE_MERGE;
59
60
    public function setDuplicateCheck($duplicateCheck)
61
    {
62
	$this->duplicateCheck = $duplicateCheck;
63
    }
64
65
    protected $wfTrigger = false;
66
67
    public function setWorkflowTrigger($wfTrigger)
68
    {
69
	$this->wfTrigger = $wfTrigger;
70
    }
71
72
    /**
73
     * Parse a Zoho Response in order to retrieve one or several ZohoBeans from it.
74
     *
75
     * @param Response $zohoResponse The response returned by the ZohoClient->call() method
76
     *
77
     * @return ZohoBeanInterface[] The array of Zoho Beans parsed from the response
78
     */
79
    protected function getBeansFromResponse(Response $zohoResponse)
80
    {
81
        $beanClass = $this->getBeanClassName();
82
        $fields = $this->getFlatFields();
83
84
        $beanArray = array();
85
86
        foreach ($zohoResponse->getRecords() as $record) {
87
88
            /** @var ZohoBeanInterface $bean */
89
            $bean = new $beanClass();
90
91
            // First, let's fill the ID.
92
            // The ID is CONTACTID or ACCOUNTID or Id depending on the Zoho type.
93
            $idName = strtoupper(rtrim($this->getModule(), 's'));
94
            if (isset($record[$idName.'ID'])) {
95
                $id = $record[$idName.'ID'];
96
            } elseif (isset($record[$idName.'_ID'])) {
97
                $id = $record[$idName.'_ID'];
98
            } else {
99
                $id = $record['Id'];
100
            }
101
            $bean->setZohoId($id);
102
            $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...
103
            $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...
104
105
            foreach ($record as $key => $value) {
106
                if (isset($fields[$key])) {
107
                    $setter = $fields[$key]['setter'];
108
109
                    switch ($fields[$key]['type']) {
110
                        case 'Date':
111
                            if ($dateObj = \DateTimeImmutable::createFromFormat('M/d/Y', $value)) {
112
                                $value = $dateObj;
113
                            } elseif ($dateObj = \DateTimeImmutable::createFromFormat('Y-m-d', $value)) {
114
                                $value = $dateObj;
115
                            } else {
116
                                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().'.');
117
                            }
118
                            break;
119
                        case 'DateTime':
120
                            $value = \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $value);
121
                            break;
122
                        case 'Boolean':
123
                            $value = ($value == 'true');
124
                            break;
125
                        default:
126
                            break;
127
                    }
128
                    $bean->$setter($value);
129
                }
130
            }
131
132
            $beanArray[] = $bean;
133
        }
134
135
        return $beanArray;
136
    }
137
138
    /**
139
     * Convert an array of ZohoBeans into a SimpleXMLElement for use when inserting/updating related records.
140
     *
141
     * @param $zohoBeans ZohoBeanInterface[]
142
     *
143
     * @return \SimpleXMLElement The SimpleXMLElement containing the XML for a request
144
     */
145
    public function toXmlRelatedRecords($zohoBeans)
146
    {
147
    	return $this->toXml($zohoBeans, 1);
148
    }
149
150
    /**
151
     * Convert an array of ZohoBeans into a SimpleXMLElement.
152
     *
153
     * @param $zohoBeans ZohoBeanInterface[]
154
     *
155
     * @return \SimpleXMLElement The SimpleXMLElement containing the XML for a request
156
     */
157
    public function toXml($zohoBeans, $isRelatedRecords = 0)
158
    {
159
        $module = $this->getModule();
160
161
        $no = 1;
162
        $module = new \SimpleXMLElement("<$module/>");
163
164
        foreach ($zohoBeans as $zohoBean) {
165
            if (!$zohoBean instanceof ZohoBeanInterface) {
166
                throw new ZohoCRMException('Zoho beans sent to save must implement the ZohoBeanInterface.');
167
            }
168
169
            $properties = $this->getFlatFields();
170
            $row = $module->addChild('row');
171
            $row->addAttribute('no', $no);
172
173
            $fl = $row->addChild('FL', $zohoBean->getZohoId());
174
            $id = 'Id';
175
            if ($isRelatedRecords) {
176
	            $idName = strtoupper(rtrim($this->getModule(), 's'));
177
	            $id = $idName . 'ID';
178
	    }
179
            $fl->addAttribute('val', $id);
180
181
            foreach ($properties as $name => $params) {
182
                $camelCaseName = $params['name'];
183
                $isDirty = $zohoBean->isDirty($camelCaseName);
184
                if (!$isDirty) {
185
                    continue;
186
                }
187
188
                $getter = $params['getter'];
189
                $value = $zohoBean->$getter();
190
191
                if (!empty($value) || is_bool($value)) {
192
193
                    // We convert the value back to a proper format if the Zoho Type is Date, DateTime or Boolean
194
                    switch ($params['type']) {
195
                        case 'Date':
196
                            /** @var \DateTime $value */
197
                            $value = $value->format('m/d/Y');
198
                            break;
199
                        case 'DateTime':
200
                            /** @var \DateTime $value */
201
                            $value = $value->format('Y-m-d H:i:s');
202
                            break;
203
                        case 'Boolean':
204
                            /** @var bool $value */
205
                            $value = $value ? 'true' : 'false';
206
                            break;
207
                        default:
208
                            break;
209
                    }
210
                }
211
212
                $fl = $row->addChild('FL', htmlspecialchars($value));
213
                $fl->addAttribute('val', $name);
214
            }
215
            ++$no;
216
        }
217
218
        return $module;
219
    }
220
221
    /**
222
     * Implements deleteRecords API method.
223
     *
224
     * @param string $id Zoho Id of the record to delete
225
     *
226
     * @throws ZohoCRMResponseException
227
     */
228
    public function delete($id)
229
    {
230
        $this->zohoClient->deleteRecords($this->getModule(), $id);
231
    }
232
233
    /**
234
     * Implements getRecordById API method.
235
     *
236
     * @param string|array $id Zoho Id of the record to retrieve OR an array of IDs
237
     *
238
     * @return ZohoBeanInterface[] The array of Zoho Beans parsed from the response
239
     *
240
     * @throws ZohoCRMResponseException
241
     */
242
    public function getById($id)
243
    {
244
        try {
245
            $module = $this->getModule();
246
            $beans = [];
247
248
            // If there's several IDs to process, we divide them by pools of 100 and implode them before requesting
249
            if (is_array($id)) {
250
                foreach (array_chunk($id, self::MAX_GET_RECORDS_BY_ID) as $pool) {
251
                    $idlist = implode(';', $pool);
252
                    $response = $this->zohoClient->getRecordById($module, $idlist);
253
                    $beans = array_merge($beans, $this->getBeansFromResponse($response));
254
                }
255
            }
256
            // if not, we simply request our record
257
            else {
258
                $response = $this->zohoClient->getRecordById($module, $id);
259
                $beans = $this->getBeansFromResponse($response);
260
                $beans = array_shift($beans);
261
            }
262
263
            return $beans;
264
        } catch (ZohoCRMResponseException $e) {
265
            // No records found? Let's return an empty array!
266
            if ($e->getCode() == 4422) {
267
                return array();
268
            } else {
269
                throw $e;
270
            }
271
        }
272
    }
273
274
    /**
275
     * Implements getRecords API method.
276
     *
277
     * @param $sortColumnString
278
     * @param $sortOrderString
279
     * @param \DateTime $lastModifiedTime
280
     * @param $selectColumns
281
     * @param $limit
282
     *
283
     * @return ZohoBeanInterface[] The array of Zoho Beans parsed from the response
284
     *
285
     * @throws ZohoCRMResponseException
286
     */
287 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...
288
    {
289
        $globalResponse = array();
290
291
        do {
292
            try {
293
                $fromIndex = count($globalResponse) + 1;
294
                $toIndex = $fromIndex + self::MAX_GET_RECORDS - 1;
295
296
                if ($limit) {
297
                    $toIndex = min($limit, $toIndex);
298
                }
299
300
                $response = $this->zohoClient->getRecords($this->getModule(), $sortColumnString, $sortOrderString, $lastModifiedTime, $selectColumns, $fromIndex, $toIndex);
301
                $beans = $this->getBeansFromResponse($response);
302
            } catch (ZohoCRMResponseException $e) {
303
                // No records found? Let's return an empty array!
304
                if ($e->getCode() == 4422) {
305
                    $beans = array();
306
                } else {
307
                    throw $e;
308
                }
309
            }
310
311
            $globalResponse = array_merge($globalResponse, $beans);
312
        } while (count($beans) == self::MAX_GET_RECORDS);
313
314
        return $globalResponse;
315
    }
316
317
    /**
318
     * Returns the list of deleted records.
319
     *
320
     * @param \DateTimeInterface|null $lastModifiedTime
321
     * @param int                     $limit
322
     *
323
     * @return array
324
     *
325
     * @throws ZohoCRMResponseException
326
     * @throws \Exception
327
     */
328 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...
329
    {
330
        $globalDeletedIDs = array();
331
332
        do {
333
            try {
334
                $fromIndex = count($globalDeletedIDs) + 1;
335
                $toIndex = $fromIndex + self::MAX_GET_RECORDS - 1;
336
337
                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...
338
                    $toIndex = min($limit - 1, $toIndex);
339
                }
340
341
                $response = $this->zohoClient->getDeletedRecordIds($this->getModule(), $lastModifiedTime, $fromIndex, $toIndex);
342
                $deletedIDs = $response->getDeletedIds();
343
            } catch (ZohoCRMResponseException $e) {
344
                // No records found? Let's return an empty array!
345
                if ($e->getZohoCode() == 4422) {
346
                    $deletedIDs = array();
347
                } else {
348
                    throw $e;
349
                }
350
            }
351
352
            $globalDeletedIDs = array_merge($globalDeletedIDs, $deletedIDs);
353
        } while (count($deletedIDs) == self::MAX_GET_RECORDS);
354
355
        return $globalDeletedIDs;
356
    }
357
358
    /**
359
     * Implements getRecords API method.
360
     *
361
     * @param string $id           Zoho Id of the record to delete
362
     * @param string $parentModule The parent module of the records
363
     * @param int    $limit        The max number of records to fetch
364
     *
365
     * @return ZohoBeanInterface[] The array of Zoho Beans parsed from the response
366
     *
367
     * @throws ZohoCRMResponseException
368
     */
369 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...
370
    {
371
        $globalResponse = array();
372
373
        do {
374
            try {
375
                $fromIndex = count($globalResponse) + 1;
376
                $toIndex = $fromIndex + self::MAX_GET_RECORDS - 1;
377
378
                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...
379
                    $toIndex = min($limit - 1, $toIndex);
380
                }
381
382
                $response = $this->zohoClient->getRelatedRecords($this->getModule(), $id, $parentModule, $fromIndex, $toIndex);
383
                $beans = $this->getBeansFromResponse($response);
384
            } catch (ZohoCRMResponseException $e) {
385
                // No records found? Let's return an empty array!
386
                if ($e->getCode() == 4422) {
387
                    $beans = array();
388
                } else {
389
                    throw $e;
390
                }
391
            }
392
393
            $globalResponse = array_merge($globalResponse, $beans);
394
        } while (count($beans) == self::MAX_GET_RECORDS);
395
396
        return $globalResponse;
397
    }
398
399
    /**
400
     * Implements searchRecords API method.
401
     *
402
     * @param string    $searchCondition  The search criteria formatted like
403
     * @param int       $limit            The maximum number of beans returned from Zoho
404
     * @param \DateTime $lastModifiedTime
405
     * @param string    $selectColumns    The list
406
     *
407
     * @return ZohoBeanInterface[] The array of Zoho Beans parsed from the response
408
     *
409
     * @throws ZohoCRMResponseException
410
     */
411 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...
412
    {
413
        $globalResponse = array();
414
415
        do {
416
            try {
417
                $fromIndex = count($globalResponse) + 1;
418
                $toIndex = $fromIndex + self::MAX_GET_RECORDS - 1;
419
420
                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...
421
                    $toIndex = min($limit - 1, $toIndex);
422
                }
423
424
                $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 411 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...
425
                $beans = $this->getBeansFromResponse($response);
426
            } catch (ZohoCRMResponseException $e) {
427
                // No records found? Let's return an empty array!
428
                if ($e->getCode() == 4422) {
429
                    $beans = array();
430
                } else {
431
                    throw $e;
432
                }
433
            }
434
435
            $globalResponse = array_merge($globalResponse, $beans);
436
        } while (count($beans) == self::MAX_GET_RECORDS);
437
438
        return $globalResponse;
439
    }
440
441
    /**
442
     * Implements insertRecords API method.
443
     *
444
     * WARNING : When setting wfTrigger to true, this method will use an API call per bean
445
     * passed in argument. This is caused by Zoho limitation which forbids triggering any
446
     * workflow when inserting several beans simultaneously.
447
     *
448
     * @param ZohoBeanInterface[] $beans          The Zoho Beans to insert in the CRM
449
     * @param bool                $wfTrigger      Whether or not the call should trigger the workflows related to a "created" event
450
     * @param int                 $duplicateCheck 1 : Throwing error when a duplicate is found; 2 : Merging with existing duplicate
451
     * @param bool                $isApproval     Whether or not to push the record into an approval sandbox first
452
     *
453
     * @throws ZohoCRMResponseException
454
     */
455
    public function insertRecords($beans, $wfTrigger = null, $duplicateCheck = null, $isApproval = null)
456
    {
457
        $records = [];
458
459
	// For duplicate check and wfTrigger, use the setting passed or the object-wide setting
460
	$duplicateCheck = $duplicateCheck ?: $this->duplicateCheck;
461
	$wfTrigger = ($wfTrigger === null ? $this->wfTrigger : $wfTrigger);
462
463
        if ($wfTrigger) {
464
            // If we trigger workflows, we trigger the insert of beans one by one.
465
            foreach ($beans as $bean) {
466
                $xmlData = $this->toXml([$bean]);
467
                $response = $this->zohoClient->insertRecords($this->getModule(), $xmlData, $wfTrigger, $duplicateCheck, $isApproval);
468
                $records = array_merge($records, $response->getRecords());
469
            }
470 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...
471
            // We can't pass more than 100 records to Zoho, so we split the request into pieces of 100
472
            foreach (array_chunk($beans, 100) as $beanPool) {
473
                $xmlData = $this->toXml($beanPool);
474
                $response = $this->zohoClient->insertRecords($this->getModule(), $xmlData, $wfTrigger, $duplicateCheck, $isApproval);
475
                $records = array_merge($records, $response->getRecords());
476
            }
477
        }
478 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...
479
            throw new ZohoCRMException('Error while inserting beans in Zoho. '.count($beans).' passed in parameter, but '.count($records).' returned.');
480
        }
481
482
        foreach ($beans as $key => $bean) {
483
            $record = $records[$key];
484
485
            if ($wfTrigger && (!isset($record['Id']) || empty($record['Id']))) {
486
                // This field is probably in error!
487
                throw new ZohoCRMException('An error occurred while inserting records and triggering workflow: '.$record['message'], $record['code']);
488
            } elseif (!$wfTrigger && substr($record['code'], 0, 1) != '2') {
489
                // This field is probably in error!
490
                throw new ZohoCRMException('An error occurred while inserting records: '.$record['message'], $record['code']);
491
            }
492
493
            $bean->setZohoId($record['Id']);
494
            $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...
495
            if ($record['Modified Time']) {
496
                $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...
497
            }
498
        }
499
    }
500
501
    /**
502
     * Implements updateRecords API method.
503
     *
504
     * @param array $beans     The list of beans to update.
505
     * @param bool  $wfTrigger Set value as true to trigger the workflow rule in Zoho
506
     *
507
     * @return Response The Response object
508
     *
509
     * @throws ZohoCRMException
510
     */
511
    public function updateRecords(array $beans, $wfTrigger = null)
512
    {
513
        $records = [];
514
515
	$wfTrigger = ($wfTrigger === null ? $this->wfTrigger : $wfTrigger);
516
	
517
        if ($wfTrigger) {
518
            // If we trigger workflows, we trigger the insert of beans one by one.
519
            foreach ($beans as $bean) {
520
                $xmlData = $this->toXml([$bean]);
521
                $response = $this->zohoClient->updateRecords($this->getModule(), $xmlData, $bean->getZohoId(), $wfTrigger);
522
                $records = array_merge($records, $response->getRecords());
523
            }
524 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...
525
            // We can't pass more than 100 records to Zoho, so we split the request into pieces of 100
526
            foreach (array_chunk($beans, 100) as $beanPool) {
527
                $xmlData = $this->toXml($beanPool);
528
                $response = $this->zohoClient->updateRecords($this->getModule(), $xmlData, null, $wfTrigger);
529
                $records = array_merge($records, $response->getRecords());
530
            }
531
        }
532 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...
533
            throw new ZohoCRMException('Error while inserting beans in Zoho. '.count($beans).' passed in parameter, but '.count($records).' returned.');
534
        }
535
536
        $exceptions = new \SplObjectStorage();
537
538
        foreach ($beans as $key => $bean) {
539
            $record = $records[$key];
540
541
            if ($wfTrigger && (!isset($record['Id']) || empty($record['Id']))) {
542
                // This field is probably in error!
543
                throw new ZohoCRMException('An error occurred while updating records and triggering workflow: '.$record['message'], $record['code']);
544
            } elseif (!$wfTrigger && substr($record['code'], 0, 1) != '2') {
545
                // This field is probably in error!
546
                $exceptions->attach($bean, new ZohoCRMException('An error occurred while updating records. '.(isset($record['message']) ? $record['message'] : ''), $record['code']));
547
                continue;
548
            }
549
550
            if ($record['Id'] != $bean->getZohoId()) {
551
                // This field is probably in error!
552
                $exceptions->attach($bean, new ZohoCRMException('An error occurred while updating records. The Zoho ID to update was '.$bean->getZohoId().', returned '.$record['Id']));
553
                continue;
554
            }
555
556
            if ($record['Modified Time']) {
557
                $bean->setModifiedTime(\DateTime::createFromFormat('Y-m-d H:i:s', $record['Modified Time']));
558
            }
559
        }
560
        if ($exceptions->count() != 0) {
561
            throw new ZohoCRMUpdateException($exceptions);
562
        }
563
    }
564
565
    /**
566
     * Implements uploadFile API method.
567
     *
568
     * @param string $id      Zoho Id of the record to retrieve
569
     * @param string $content The string containing the file
570
     *
571
     * @return Response The Response object
572
     *
573
     * @throws ZohoCRMResponseException
574
     */
575
    public function uploadFile($id, $content)
576
    {
577
        return $this->zohoClient->uploadFile($this->getModule(), $id, $content);
578
    }
579
580
    /**
581
     * Implements downloadFile API method.
582
     *
583
     * @param string $id unique ID of the attachment
584
     *
585
     * @return Response The Response object
586
     */
587
    public function downloadFile($id)
588
    {
589
        return $this->zohoClient->downloadFile($this->getModule(), $id);
590
    }
591
592
    /**
593
     * Saves the bean or array of beans passed in Zoho.
594
     * It will perform an insert if the bean has no ZohoID or an update if the bean has a ZohoID.
595
     *
596
     * @param array|object $beans A bean or an array of beans.
597
     *
598
     * TODO: isApproval is not used by each module.
599
     * TODO: wfTrigger only usable for a single record update/insert.
600
     */
601
    public function save($beans, $wfTrigger = false, $duplicateCheck = null, $isApproval = false)
602
    {
603
	// For duplicate check and wfTrigger, use the setting passed or the object-wide setting
604
	$duplicateCheck = $duplicateCheck ?: $this->duplicateCheck;
605
	$wfTrigger = ($wfTrigger === null ? $this->wfTrigger : $wfTrigger);
606
	
607
        if (!is_array($beans)) {
608
            $beans = [$beans];
609
        }
610
611
        $toInsert = [];
612
        $toUpdate = [];
613
614
        foreach ($beans as $bean) {
615
            if ($bean->getZohoId()) {
616
                $toUpdate[] = $bean;
617
            } else {
618
                $toInsert[] = $bean;
619
            }
620
        }
621
622
        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...
623
            $this->insertRecords($toInsert, $wfTrigger, $duplicateCheck, $isApproval);
624
        }
625
        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...
626
            $this->updateRecords($toUpdate, $wfTrigger);
627
        }
628
    }
629
}
630