diff --git a/README.md b/README.md index 3d1e2cd..65550b2 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,11 @@ Use the Vtiger webservice (REST) API from within Laravel for the following opera - Retrieve - Update - Delete +- Search - Query - Describe -See [Third Party App Integration (REST APIs)](http://community.vtiger.com/help/vtigercrm/developers/third-party-app-integration.html) +See [Third Party App Integration (REST APIs)](http://community.vtiger.com/help/vtigercrm/developers/third-party-app-integration.html) ## Installation, Configuration and Usage @@ -46,7 +47,6 @@ See [Third Party App Integration (REST APIs)](http://community.vtiger.com/help/v - In your application, edit *config/vtiger.php* and replace the following array values - Set the url to the https://{DOMAIN_NAME}/webservice.php - Set the username and accesskey with your CRM username and access key. - - Set the session drive to either file or reddis - Set persistconnection to false if you want a fresh login with each request |key |value | @@ -54,7 +54,6 @@ See [Third Party App Integration (REST APIs)](http://community.vtiger.com/help/v |url |http://www.example.com/webservice.php| |username |API | |accesskey |irGsy9HB0YOZdEA | - |sessiondriver |file | |persistconnection|true | |max_retries |10 | @@ -70,7 +69,7 @@ use Vtiger; #### Create -To insert a record into the CRM, first create an array of data to insert. Don't forget the added the id of the `assigned_user_id` (i.e. '4x12') otherwise the insert will fail as `assigned_user_id` is a mandatory field. +To insert a record into the CRM, first create an array of data to insert. Don't forget the added the id of the `assigned_user_id` (i.e. '4x12') otherwise the insert will fail as `assigned_user_id` is a mandatory field. ```php $data = array( 'assigned_user_id' => '', @@ -122,6 +121,26 @@ $obj = Vtiger::retrieve($id); var_dump($obj); ``` +#### Search + +This function is a sql query builder wrapped around the query function. Accepts instance of laravels QueryBuilder. +```php +$query = DB::table('Leads')->select('id', 'firstname', 'lastname')->where('firstname', 'John'); + +$obj = Vtiger::search('Leads', $query); + +//loop over result +foreach($obj->result as $result) { + // do something +} +``` + +By default the function will quote but not escape your inputs, if you wish for your data to not be quoted, set the 3rd paramater to false like so: +```php +$obj = Vtiger::search('Leads', $query, false); +``` + +Also keep in mind that Victiger has several limitations on it's sql query capabilities. You can not use conditional grouping i.e "where (firstname = 'John' AND 'lastname = 'Doe') OR (firstname = 'Jane' AND lastname = 'Smith') will fail. #### Query To use the [Query Operation](http://community.vtiger.com/help/vtigercrm/developers/third-party-app-integration.html#query-operation), you first need to create a SQL query. diff --git a/src/Config/config.php b/src/Config/config.php index 53ded3f..89da684 100644 --- a/src/Config/config.php +++ b/src/Config/config.php @@ -5,7 +5,6 @@ 'url' => 'path/to/vtiger/webservice.php', 'username' => '', 'accesskey' => '', - 'sessiondriver' => 'file', //reddis or file 'persistconnection' => true, 'max_retries' => 10 ]; diff --git a/src/Vtiger.php b/src/Vtiger.php index 4aaf78a..b623f0e 100644 --- a/src/Vtiger.php +++ b/src/Vtiger.php @@ -5,12 +5,10 @@ use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Client; use InvalidArgumentException; -use Mockery\CountValidator\Exception; use Psr\Http\Message\ResponseInterface; -use \Illuminate\Contracts\Filesystem\FileNotFoundException; -use Storage; use Config; -use Redis; +use Cache; +use DB; /** * Laravel wrapper for the VTgier API @@ -20,7 +18,6 @@ */ class Vtiger { - /** @var VtigerErrorElement[] */ private $vTigerErrors; @@ -33,9 +30,6 @@ class Vtiger /** @var string */ protected $accessKey; - /** @var string */ - protected $sessionDriver; - /** @var string */ protected $persistConnection; @@ -56,7 +50,6 @@ public function __construct() $this->url = Config::get('vtiger.url'); $this->username = Config::get('vtiger.username'); $this->accessKey = Config::get('vtiger.accesskey'); - $this->sessionDriver = Config::get('vtiger.sessiondriver'); $this->persistConnection = Config::get('vtiger.persistconnection'); $this->maxRetries = Config::get('vtiger.max_retries'); @@ -65,14 +58,14 @@ public function __construct() 1 => new VtigerErrorElement('API request did not complete correctly - Response code: ', 1), 2 => new VtigerErrorElement('Success property not set on VTiger response', 2), 3 => new VtigerErrorElement('Error property not set on VTiger response when success is false', 3), - 4 => new VtigerErrorElement('Session driver type of ' . $this->sessionDriver . ' is not supported', 4), - 5 => new VtigerErrorElement('Could not complete login request within ' . $this->maxRetries . ' tries', 5), + 4 => new VtigerErrorElement('There are no search fields in the array', 4), + 5 => new VtigerErrorElement('Could not complete login request within ' . $this->maxRetries . ' tries', 5), 6 => new VtigerErrorElement( 'Could not complete get token request within ' . $this->maxRetries . ' tries', 6 ), 7 => new VtigerErrorElement('Guzzle ran into problems - ', 7), - 8 => new VtigerErrorElement('Redis problem - ', 8), + 8 => new VtigerErrorElement('Laravel Cache problem', 8), ]; try { @@ -80,7 +73,6 @@ public function __construct() } catch (InvalidArgumentException $e) { throw VtigerError::init($this->vTigerErrors, 7, $e->getMessage()); } - } /** @@ -109,34 +101,13 @@ public function connection($url, $username, $accessKey) */ protected function sessionId() { - // Check the session file exists - switch ($this->sessionDriver) { - case "file": - if (Storage::disk('local')->exists('session.json')) { - try { - $sessionData = json_decode(Storage::disk('local')->get('session.json')); - } catch (FileNotFoundException $e) { - throw VtigerError::init($this->vTigerErrors, 7, $e->getMessage()); - } - } - break; - case "redis": - $sessionData = json_decode(Redis::get('clystnet_vtiger')); - - if (!$sessionData) { - throw VtigerError::init($this->vTigerErrors, 8, 'Could not get the session data from index clystnet_vtiger'); - } - break; - default: - throw new VtigerError("Session driver type of " . $this->sessionDriver . " is not supported", 4); - } + // Get the sessionData from the cache + $sessionData = json_decode(Cache::get('clystnet_vtiger')); if (isset($sessionData)) { - if ( - isset($sessionData) && + if (isset($sessionData) && property_exists($sessionData, 'expireTime') && - property_exists($sessionData, 'token') - ) { + property_exists($sessionData, 'token')) { if ($sessionData->expireTime < time() || empty($sessionData->token)) { $sessionData = $this->storeSession(); } @@ -195,25 +166,17 @@ protected function login($sessionData) } while (!isset($loginResult->success) && $tryCounter <= $this->maxRetries); if ($tryCounter >= $this->maxRetries) { - throw new VtigerError("Could not complete login request within " . $this->maxRetries . " tries", 5); + throw new VtigerError('Could not complete login request within ' . $this->maxRetries . ' tries', 5); } // If api login failed if ($response->getStatusCode() !== 200 || !$loginResult->success) { if (!$loginResult->success) { - if ($loginResult->error->code == "INVALID_USER_CREDENTIALS" || $loginResult->error->code == "INVALID_SESSIONID") { - if ($this->sessionDriver == 'file') { - if (Storage::disk('local')->exists('session.json')) { - try { - Storage::disk('local')->delete('session.json'); - } catch (FileNotFoundException $e) { - throw VtigerError::init($this->vTigerErrors, 7, $e->getMessage()); - } - } - } elseif ($this->sessionDriver == 'redis') { - if (Redis::del('clystnet_vtiger') < 1) { - throw VtigerError::init($this->vTigerErrors, 8, 'Nothing to delete for index clystnet_vtiger'); - } + if ($loginResult->error->code == 'INVALID_USER_CREDENTIALS' || $loginResult->error->code == 'INVALID_SESSIONID') { + if (!Cache::has('clystnet_vtiger')) { + throw VtigerError::init($this->vTigerErrors, 8, 'Nothing to delete for index clystnet_vtiger'); + } else { + Cache::forget('clystnet_vtiger'); } } else { $this->_processResult($response); @@ -225,26 +188,12 @@ protected function login($sessionData) // login ok so get sessionid and update our session $sessionId = $loginResult->result->sessionName; - switch ($this->sessionDriver) { - case "file": - if (Storage::disk('local')->exists('session.json')) { - try { - $json = json_decode(Storage::disk('local')->get('session.json')); - $json->sessionid = $sessionId; - Storage::disk('local')->put('session.json', json_encode($json)); - } catch (FileNotFoundException $e) { - throw VtigerError::init($this->vTigerErrors, 7, $e->getMessage()); - } - } - break; - case "redis": - Redis::incr('loggedin'); - $json = json_decode(Redis::get('clystnet_vtiger')); - $json->sessionid = $sessionId; - Redis::set('clystnet_vtiger', json_encode($json)); - break; - default: - throw new VtigerError("Session driver type of " . $this->sessionDriver . " is not supported", 4); + if (Cache::has('clystnet_vtiger')) { + $json = json_decode(Cache::pull('clystnet_vtiger')); + $json->sessionid = $sessionId; + Cache::forever('clystnet_vtiger', json_encode($json)); + } else { + throw VtigerError::init($this->vTigerErrors, 8, 'There is no key for index clystnet_vtiger.'); } } @@ -262,19 +211,7 @@ protected function storeSession() $updated = $this->getToken(); $output = (object)$updated; - if ($this->sessionDriver == 'file') { - try { - Storage::disk('local')->put('session.json', json_encode($output)); - } catch (FileNotFoundException $e) { - throw VtigerError::init($this->vTigerErrors, 7, $e->getMessage()); - } - } elseif ($this->sessionDriver == 'redis') { - $setResult = Redis::set('clystnet_vtiger', json_encode($output)); - - if (!$setResult) { - throw VtigerError::init($this->vTigerErrors, 8, 'Could not set the session data in index clystnet_vtiger'); - } - } + $cacheResult = Cache::forever('clystnet_vtiger', json_encode($output)); return $output; } @@ -305,17 +242,17 @@ protected function getToken() } while (!isset($this->_processResponse($response)->success) && $tryCounter <= $this->maxRetries); if ($tryCounter >= $this->maxRetries) { - throw new VtigerError("Could not complete get token request within " . $this->maxRetries . " tries", 6); + throw new VtigerError('Could not complete get token request within ' . $this->maxRetries . ' tries', 6); } // decode the response $challenge = $this->_processResult($response); // Everything ok so create a token from response - $output = array( + $output = [ 'token' => $challenge->result->token, 'expireTime' => $challenge->result->expireTime, - ); + ]; return $output; } @@ -337,12 +274,15 @@ protected function close($sessionId) try { // send a request to close current connection $response = $this->guzzleClient->request( - 'POST', $this->url, [ - 'query' => [ - 'operation' => 'logout', - 'sessionName' => $sessionId + 'POST', + $this->url, + [ + 'query' => [ + 'operation' => 'logout', + 'sessionName' => $sessionId + ] ] - ]); + ); } catch (GuzzleException $e) { throw VtigerError::init($this->vTigerErrors, 7, $e->getMessage()); } @@ -380,6 +320,23 @@ public function query($query) return $this->_processResult($response); } + public function search($query, $quote = true) + { + $bindings = $query->getBindings(); + $queryString = $query->toSQL(); + + foreach ($bindings as $binding) { + if ($quote) { + $queryString = preg_replace('/\?/', DB::connection()->getPdo()->quote($binding), $queryString, 1); + } else { + $queryString = preg_replace('/\?/', $binding, $queryString, 1); + } + } + $queryString = str_replace('`', '', $queryString) . ';'; + + return $this->query($queryString); + } + /** * Retreive a record from the VTiger API * Format of id must be {moudler_code}x{item_id}, e.g 4x12 @@ -402,7 +359,7 @@ public function retrieve($id) 'id' => $id ] ]); - } catch (GuzzleException $e) { + } catch (GuzzleException $e) { throw VtigerError::init($this->vTigerErrors, 7, $e->getMessage()); } @@ -444,7 +401,7 @@ public function create($elem, $data) 'elementType' => $elem ] ]); - } catch (GuzzleException $e) { + } catch (GuzzleException $e) { throw VtigerError::init($this->vTigerErrors, 7, $e->getMessage()); } @@ -476,7 +433,7 @@ public function update($object) 'element' => json_encode($object), ] ]); - } catch (GuzzleException $e) { + } catch (GuzzleException $e) { throw VtigerError::init($this->vTigerErrors, 7, $e->getMessage()); } @@ -531,13 +488,16 @@ public function describe($elementType) try { // send a request to describe a module (which returns a list of available fields) for a Vtiger module $response = $this->guzzleClient->request( - 'GET', $this->url, [ - 'query' => [ - 'operation' => 'describe', - 'sessionName' => $sessionId, - 'elementType' => $elementType + 'GET', + $this->url, + [ + 'query' => [ + 'operation' => 'describe', + 'sessionName' => $sessionId, + 'elementType' => $elementType + ] ] - ]); + ); } catch (GuzzleException $e) { throw VtigerError::init($this->vTigerErrors, 7, $e->getMessage()); } @@ -618,8 +578,6 @@ protected function _processResponseError($processedData) if (!isset($processedData->error)) { throw VtigerError::init($this->vTigerErrors, 3); } - throw VtigerError::init($this->vTigerErrors, 0, $processedData->error->message); } - }