Completed
Push — master ( a8d3eb...b61cd2 )
by Zhmayev
02:08 queued 42s
created

Entities::getQueryString()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 12
nop 5
dl 0
loc 22
rs 8.9457
c 0
b 0
f 0
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;
45
46
    /**
47
     * Class constructor
48
     * @param object $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 array  Entity data
61
     */
62
    public function findOneByID($moduleName, $entityID, array $select = [ ])
63
    {
64
        $entityID = $this->wsClient->modules->getTypedID($moduleName, $entityID);
65
        $record = $this->wsClient->invokeOperation('retrieve', ['id' => $entityID], 'GET');
66
        if (!is_array($record))
0 ignored issues
show
Coding Style Best Practice introduced by
It is generally a best practice to always use braces with control structures.

Adding braces to control structures avoids accidental mistakes as your code changes:

// Without braces (not recommended)
if (true)
    doSomething();

// Recommended
if (true) {
    doSomething();
}
Loading history...
67
            return null;
68
69
        return (empty($select))
70
            ? $record
71
            : array_intersect_key($record, array_flip($select));
72
    }
73
74
    /**
75
     * Retrieve the entity matching a list of constraints
76
     * @param  string  $moduleName   The name of the module / entity type
77
     * @param  array   $params  Data used to find a matching entry
78
     * @return array   $select  The list of fields to select (defaults to SQL-like '*' - all the fields)
79
     * @return array  The matching record
80
     */
81
    public function findOne($moduleName, array $params, array $select = [ ])
82
    {
83
        $entityID = $this->getID($moduleName, $params);
84
        return (empty($entityID))
85
            ? null
86
            : $this->findOneByID($moduleName, $entityID, $select);
87
    }
88
89
    /**
90
     * Retrieves the ID of the entity matching a list of constraints + prepends '<module_id>x' string to it
91
     * @param  string $moduleName   The name of the module / entity type
92
     * @param  array   $params  Data used to find a matching entry
93
     * @return string  Type ID (a numeric ID + '<module_id>x')
94
     */
95
    public function getID($moduleName, array $params)
96
    {
97
        $query = self::getQueryString($moduleName, $params, [ 'id' ], 1);
98
        $records = $this->wsClient->runQuery($query);
99
        if (false === $records || !is_array($records) || empty($records)) {
100
            return null;
101
        }
102
103
        $record = $records[0];
104
        return (!is_array($record) || !isset($record[ 'id' ]) || empty($record[ 'id' ]))
105
            ? null
106
            : $record[ 'id' ];
107
    }
108
109
    /**
110
     * Retrieve a numeric ID of the entity matching a list of constraints
111
     * @param  string  $moduleName   The name of the module / entity type
112
     * @param  array   $params  Data used to find a matching entry
113
     * @return integer  Numeric ID
114
     */
115
    public function getNumericID($moduleName, array $params)
116
    {
117
        $entityID = $this->getID($moduleName, $params);
118
        $entityIDParts = explode('x', $entityID, 2);
119
        return (is_array($entityIDParts) && count($entityIDParts) === 2)
120
            ? intval($entityIDParts[ 1 ])
121
            : -1;
122
    }
123
124
    /**
125
     * Creates an entity for the giving module
126
     * @param  string  $moduleName   Name of the module / entity type for which the entry has to be created
127
     * @param  array  $params Entity data
128
     * @return array  Entity creation results
129
     */
130
    public function createOne($moduleName, array $params)
131
    {
132
        if (!is_assoc_array($params)) {
133
            throw new WSException(
134
                "You have to specify at least one search parameter (prop => value) 
135
                in order to be able to create an entity"
136
            );
137
        }
138
139
        // Assign record to logged in user if not specified
140
        if (!isset($params[ 'assigned_user_id' ])) {
141
            $currentUser = $this->wsClient->getCurrentUser();
142
            $params[ 'assigned_user_id' ] = $currentUser[ 'id' ];
143
        }
144
145
        $requestData = [
146
            'elementType' => $moduleName,
147
            'element'     => json_encode($params)
148
        ];
149
150
        return $this->wsClient->invokeOperation('create', $requestData);
151
    }
152
153
    /**
154
     * Updates an entity
155
     * @param  string $moduleName   The name of the module / entity type
156
     * @param  array $params Entity data
157
     * @return array  Entity update result
158
     */
159
    public function updateOne($moduleName, $entityID, array $params)
160
    {
161
        if (!is_assoc_array($params)) {
162
            throw new WSException(
163
                "You have to specify at least one search parameter (prop => value) 
164
                in order to be able to update the entity(ies)"
165
            );
166
        }
167
168
        // Fail if no ID was supplied
169
        if (empty($entityID)) {
170
            throw new WSException("The list of contraints must contain a valid ID");
171
        }
172
173
        // Preprend so-called moduleid if needed
174
        $entityID = $this->wsClient->modules->getTypedID($moduleName, $entityID);
175
176
        // Check if the entity exists + retrieve its data so it can be used below
177
        $entityData = $this->findOneByID($moduleName, $entityID);
178
        if ($entityData === false && !is_array($entityData)) {
179
            throw new WSException("Such entity doesn't exist, so it cannot be updated");
180
        }
181
182
        // The new data overrides the existing one needed to provide
183
        // mandatory field values to WS 'update' operation
184
        $params = array_merge(
185
            $entityData,
186
            $params
187
        );
188
189
        $requestData = [
190
            'elementType' => $moduleName,
191
            'element'     => json_encode($params)
192
        ];
193
194
        return $this->wsClient->invokeOperation('update', $requestData);
195
    }
196
197
    /**
198
     * Provides entity removal functionality
199
     * @param  string $moduleName   The name of the module / entity type
200
     * @param  string $entityID The ID of the entity to delete
201
     * @return array  Removal status object
202
     */
203
    public function deleteOne($moduleName, $entityID)
204
    {
205
        // Preprend so-called moduleid if needed
206
        $entityID = $this->wsClient->modules->getTypedID($moduleName, $entityID);
207
        return $this->wsClient->invokeOperation('delete', [ 'id' => $entityID ]);
208
    }
209
210
    /**
211
     * Retrieves multiple records using module name and a set of constraints
212
     * @param  string   $moduleName  The name of the module / entity type
213
     * @param  array    $params  Data used to find matching entries
214
     * @return array    $select  The list of fields to select (defaults to SQL-like '*' - all the fields)
215
     * @return integer  $limit   Limit the list of entries to N records (acts like LIMIT in SQL)
216
     * @return integer  $offset  Integer values to specify the offset of the query
217
     * @return array  The array containing matching entries or false if nothing was found
218
     */
219
    public function findMany($moduleName, array $params, array $select = [ ], $limit = 0, $offset = 0)
220
    {
221
        if (!is_array($params) || (!empty($params) && !is_assoc_array($params))) {
222
            throw new WSException(
223
                "You have to specify at least one search parameter (prop => value) 
224
                in order to be able to retrieve entity(ies)"
225
            );
226
        }
227
228
        // Builds the query
229
        $query = self::getQueryString($moduleName, $params, $select, $limit, $offset);
230
231
        // Run the query
232
        $records = $this->wsClient->runQuery($query);
233
        if (false === $records || !is_array($records) || empty($records)) {
234
            return null;
235
        }
236
237
        return $records;
238
    }
239
240
    /**
241
     * Sync will return a sync result object containing details of changes after modifiedTime
242
     * @param  integer [$modifiedTime = null]    The date of the first change
243
     * @param  string [$moduleName = null]   The name of the module / entity type
244
     * @param  string [$syncType = null]   Sync type determines the scope of the query
245
     * @return array  Sync result object
246
     */
247
    public function sync($modifiedTime = null, $moduleName = null, $syncType = null)
248
    {
249
        $modifiedTime = (empty($modifiedTime))
250
            ? strtotime('today midnight')
251
            : intval($modifiedTime);
252
253
        $requestData = [
254
            'modifiedTime' => $modifiedTime
255
        ];
256
257
        if (!empty($moduleName)) {
258
            $requestData[ 'elementType' ] = $moduleName;
259
        }
260
261
        if ($syncType) {
262
            $requestData[ 'syncType' ] = $syncType;
263
        }
264
265
        return $this->wsClient->invokeOperation('sync', $requestData, 'GET');
266
    }
267
268
    /**
269
     * Builds the query using the supplied parameters
270
     * @access public
271
     * @static
272
     * @param  string   $moduleName  The name of the module / entity type
273
     * @param  array    $params  Data used to find matching entries
274
     * @return string   $select  The list of fields to select (defaults to SQL-like '*' - all the fields)
275
     * @return integer  $limit   Limit the list of entries to N records (acts like LIMIT in SQL)
276
     * @return integer  $offset  Integer values to specify the offset of the query
277
     * @return string   The query build out of the supplied parameters
278
     */
279
    public static function getQueryString($moduleName, array $params, array $select = [ ], $limit = 0, $offset = 0)
280
    {
281
        $criteria = array();
282
        $select = (empty($select)) ? '*' : implode(',', $select);
283
        $query = sprintf("SELECT %s FROM $moduleName", $select);
284
        
285
        if (!empty($params)) {
286
            foreach ($params as $param => $value) {
287
                $criteria[ ] = "{$param} LIKE '{$value}'";
288
            }
289
290
            $query .= sprintf(' WHERE %s', implode(" AND ", $criteria));
291
        }
292
293
        if (intval($limit) > 0) {
294
            $query .= (intval($offset) > 0)
295
                ? sprintf(" LIMIT %s, %s", intval($offset), intval($limit))
296
                : sprintf(" LIMIT %s", intval($limit));
297
        }
298
299
        return $query;
300
    }
301
}
302