1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Vtiger Web Services PHP Client Library |
4
|
|
|
* |
5
|
|
|
* The MIT License (MIT) |
6
|
|
|
* |
7
|
|
|
* Copyright (c) 2015, Zhmayev Yaroslav <[email protected]> |
8
|
|
|
* |
9
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy |
10
|
|
|
* of this software and associated documentation files (the "Software"), to deal |
11
|
|
|
* in the Software without restriction, including without limitation the rights |
12
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13
|
|
|
* copies of the Software, and to permit persons to whom the Software is |
14
|
|
|
* furnished to do so, subject to the following conditions: |
15
|
|
|
* |
16
|
|
|
* The above copyright notice and this permission notice shall be included in |
17
|
|
|
* all copies or substantial portions of the Software. |
18
|
|
|
* |
19
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25
|
|
|
* THE SOFTWARE. |
26
|
|
|
* |
27
|
|
|
* @author Zhmayev Yaroslav <[email protected]> |
28
|
|
|
* @copyright 2015-2016 Zhmayev Yaroslav |
29
|
|
|
* @license The MIT License (MIT) |
30
|
|
|
*/ |
31
|
|
|
|
32
|
|
|
namespace Salaros\Vtiger\VTWSCLib; |
33
|
|
|
|
34
|
|
|
use Salaros\Vtiger\VTWSCLib\WSClient; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Vtiger Web Services PHP Client Session class |
38
|
|
|
* |
39
|
|
|
* Class Entities |
40
|
|
|
* @package Salaros\Vtiger\VTWSCLib |
41
|
|
|
*/ |
42
|
|
|
class Entities |
43
|
|
|
{ |
44
|
|
|
private $wsClient = null; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Class constructor |
48
|
|
|
* @param string $wsClient Parent WSClient instance |
49
|
|
|
*/ |
50
|
|
|
public function __construct($wsClient) |
51
|
|
|
{ |
52
|
|
|
$this->wsClient = $wsClient; |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Retrieves an entity by ID |
57
|
|
|
* @param string $moduleName The name of the module / entity type |
58
|
|
|
* @param string $entityID The ID of the entity to retrieve |
59
|
|
|
* @return array $select The list of fields to select (defaults to SQL-like '*' - all the fields) |
60
|
|
|
* @return boolean Entity data |
61
|
|
|
*/ |
62
|
|
|
public function findOneByID($moduleName, $entityID, array $select = [ ]) |
63
|
|
|
{ |
64
|
|
|
return $this->findOne($moduleName, [ 'id' => $entityID ], $select); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Retrieve the entity matching a list of constraints |
69
|
|
|
* @param string $moduleName The name of the module / entity type |
70
|
|
|
* @param array $params Data used to find a matching entry |
71
|
|
|
* @return array $select The list of fields to select (defaults to SQL-like '*' - all the fields) |
72
|
|
|
* @return integer The matching record |
73
|
|
|
*/ |
74
|
|
View Code Duplication |
public function findOne($moduleName, array $params, array $select = [ ]) |
|
|
|
|
75
|
|
|
{ |
76
|
|
|
$records = $this->findMany($moduleName, $params, $select, 1); |
77
|
|
|
if (false === $records || !isset($records[ 0 ])) { |
78
|
|
|
return false; |
|
|
|
|
79
|
|
|
} |
80
|
|
|
return $records[ 0 ]; |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Retrieves the ID of the entity matching a list of constraints + prepends '<module_id>x' string to it |
85
|
|
|
* @param string $moduleName The name of the module / entity type |
86
|
|
|
* @param array $params Data used to find a matching entry |
87
|
|
|
* @return integer Type ID (a numeric ID + '<module_id>x') |
88
|
|
|
*/ |
89
|
|
View Code Duplication |
public function getID($moduleName, array $params) |
|
|
|
|
90
|
|
|
{ |
91
|
|
|
$record = $this->findOne($moduleName, $params, [ 'id' ]); |
92
|
|
|
if (false === $record || !isset($record[ 'id' ]) || empty($record[ 'id' ])) { |
93
|
|
|
return false; |
|
|
|
|
94
|
|
|
} |
95
|
|
|
return $record[ 'id' ]; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* Retrieve a numeric ID of the entity matching a list of constraints |
100
|
|
|
* @param string $moduleName The name of the module / entity type |
101
|
|
|
* @param array $params Data used to find a matching entry |
102
|
|
|
* @return integer Numeric ID |
103
|
|
|
*/ |
104
|
|
|
public function getNumericID($moduleName, array $params) |
105
|
|
|
{ |
106
|
|
|
$entityID = $this->getID($moduleName, $params); |
107
|
|
|
$entityIDParts = explode('x', $entityID, 2); |
108
|
|
|
return (is_array($entityIDParts) && count($entityIDParts) === 2) |
109
|
|
|
? intval($entityIDParts[ 1 ]) |
110
|
|
|
: -1; |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Creates an entity for the giving module |
115
|
|
|
* @param string $moduleName Name of the module / entity type for which the entry has to be created |
116
|
|
|
* @param array $params Entity data |
117
|
|
|
* @return array Entity creation results |
118
|
|
|
*/ |
119
|
|
|
public function createOne($moduleName, array $params) |
120
|
|
|
{ |
121
|
|
|
if (!is_assoc_array($params)) { |
122
|
|
|
throw new WSException( |
123
|
|
|
"You have to specify at least one search parameter (prop => value) |
124
|
|
|
in order to be able to create an entity" |
125
|
|
|
); |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
// Assign record to logged in user if not specified |
129
|
|
|
if (!isset($params[ 'assigned_user_id' ])) { |
130
|
|
|
$currentUser = $this->wsClient->getCurrentUser(); |
|
|
|
|
131
|
|
|
$params[ 'assigned_user_id' ] = $currentUser[ 'id' ]; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
$requestData = [ |
135
|
|
|
'elementType' => $moduleName, |
136
|
|
|
'element' => json_encode($params) |
137
|
|
|
]; |
138
|
|
|
|
139
|
|
|
return $this->wsClient->invokeOperation('create', $requestData); |
|
|
|
|
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* Updates an entity |
144
|
|
|
* @param string $moduleName The name of the module / entity type |
145
|
|
|
* @param array $params Entity data |
146
|
|
|
* @return array Entity update result |
147
|
|
|
*/ |
148
|
|
|
public function updateOne($moduleName, $entityID, array $params) |
149
|
|
|
{ |
150
|
|
|
if (!is_assoc_array($params)) { |
151
|
|
|
throw new WSException( |
152
|
|
|
"You have to specify at least one search parameter (prop => value) |
153
|
|
|
in order to be able to update the entity(ies)" |
154
|
|
|
); |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
// Fail if no ID was supplied |
158
|
|
|
if (empty($entityID)) { |
159
|
|
|
throw new WSException("The list of contraints must contain a valid ID"); |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
// Preprend so-called moduleid if needed |
163
|
|
|
$entityID = $this->wsClient->modules->getTypedID($moduleName, $entityID); |
164
|
|
|
|
165
|
|
|
// Check if the entity exists + retrieve its data so it can be used below |
166
|
|
|
$entityData = $this->findOneByID($moduleName, $entityID); |
167
|
|
|
if ($entityData === false && !is_array($entityData)) { |
168
|
|
|
throw new WSException("Such entity doesn't exist, so it cannot be updated"); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
// The new data overrides the existing one needed to provide |
172
|
|
|
// mandatory field values to WS 'update' operation |
173
|
|
|
$params = array_merge( |
174
|
|
|
$entityData, |
175
|
|
|
$params |
176
|
|
|
); |
177
|
|
|
|
178
|
|
|
$requestData = [ |
179
|
|
|
'elementType' => $moduleName, |
180
|
|
|
'element' => json_encode($params) |
181
|
|
|
]; |
182
|
|
|
|
183
|
|
|
return $this->wsClient->invokeOperation('update', $requestData); |
|
|
|
|
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* Provides entity removal functionality |
188
|
|
|
* @param string $moduleName The name of the module / entity type |
189
|
|
|
* @param string $entityID The ID of the entity to delete |
190
|
|
|
* @return array Removal status object |
191
|
|
|
*/ |
192
|
|
|
public function deleteOne($moduleName, $entityID) |
193
|
|
|
{ |
194
|
|
|
// Preprend so-called moduleid if needed |
195
|
|
|
$entityID = $this->wsClient->modules->getTypedID($moduleName, $entityID); |
196
|
|
|
return $this->wsClient->invokeOperation('delete', [ 'id' => $entityID ]); |
|
|
|
|
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* Retrieves multiple records using module name and a set of constraints |
201
|
|
|
* @param string $moduleName The name of the module / entity type |
202
|
|
|
* @param array $params Data used to find matching entries |
203
|
|
|
* @return array $select The list of fields to select (defaults to SQL-like '*' - all the fields) |
204
|
|
|
* @return integer $limit limit the list of entries to N records (acts like LIMIT in SQL) |
205
|
|
|
* @return bool|array The array containing matching entries or false if nothing was found |
206
|
|
|
*/ |
207
|
|
|
public function findMany($moduleName, array $params, array $select = [ ], $limit = 0) |
208
|
|
|
{ |
209
|
|
|
if (!is_assoc_array($params)) { |
210
|
|
|
throw new WSException( |
211
|
|
|
"You have to specify at least one search parameter (prop => value) |
212
|
|
|
in order to be able to retrieve entity(ies)" |
213
|
|
|
); |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
// Builds the query |
217
|
|
|
$query = self::getQueryString($moduleName, $params, $select, $limit); |
218
|
|
|
|
219
|
|
|
// Run the query |
220
|
|
|
$records = $this->wsClient->runQuery($query); |
|
|
|
|
221
|
|
|
if (false === $records || !is_array($records) || (count($records) <= 0)) { |
222
|
|
|
return false; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
return $records; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* Sync will return a sync result object containing details of changes after modifiedTime |
230
|
|
|
* @param integer [$modifiedTime = null] The date of the first change |
231
|
|
|
* @param string [$moduleName = null] The name of the module / entity type |
232
|
|
|
* @return array Sync result object |
233
|
|
|
*/ |
234
|
|
|
public function sync($modifiedTime = null, $moduleName = null) |
235
|
|
|
{ |
236
|
|
|
$modifiedTime = (empty($modifiedTime)) |
237
|
|
|
? strtotime('today midnight') |
238
|
|
|
: intval($modifiedTime); |
239
|
|
|
|
240
|
|
|
$requestData = [ |
241
|
|
|
'modifiedTime' => $modifiedTime |
242
|
|
|
]; |
243
|
|
|
|
244
|
|
|
if (!empty($moduleName)) { |
245
|
|
|
$requestData[ 'elementType' ] = $moduleName; |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
return $this->wsClient->invokeOperation('sync', $requestData, true); |
|
|
|
|
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* Builds the query using the supplied parameters |
253
|
|
|
* @access public |
254
|
|
|
* @static |
255
|
|
|
* @param string $moduleName The name of the module / entity type |
256
|
|
|
* @param array $params Data used to find matching entries |
257
|
|
|
* @return string $select The list of fields to select (defaults to SQL-like '*' - all the fields) |
258
|
|
|
* @return string $limit limit the list of entries to N records (acts like LIMIT in SQL) |
259
|
|
|
* @return string The query build out of the supplied parameters |
260
|
|
|
*/ |
261
|
|
|
public static function getQueryString($moduleName, array $params, array $select = [ ], $limit = 0) |
262
|
|
|
{ |
263
|
|
|
$criteria = array(); |
264
|
|
|
$select = (empty($select)) ? '*' : implode(',', $select); |
265
|
|
|
$query = sprintf("SELECT %s FROM $moduleName WHERE ", $select); |
266
|
|
|
foreach ($params as $param => $value) { |
267
|
|
|
$criteria[ ] = "{$param} LIKE '{$value}'"; |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
$query .= implode(" AND ", $criteria); |
271
|
|
|
if (intval($limit) > 0) { |
272
|
|
|
$query .= sprintf(" LIMIT %s", intval($limit)); |
273
|
|
|
} |
274
|
|
|
return $query; |
275
|
|
|
} |
276
|
|
|
} |
277
|
|
|
|
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.