Skip to content

Commit c3c17f3

Browse files
committed
* All config-related functional fully moved to Config
* “customfields” encoding moved to the config as well * Config refactored * Connector now store the config inside after the initialization * Connector simplified dramatically, become slick and readable * All code was heavily tested, linted, formatted * demo added * facade now cover three basic functions: — to run it (initiate entity) and connect, allowing to avoid any internal class usage outside of the module — to make calls directly through the Facade — to create an instance of the Connector and use it directly (so-called “expert mode”) * Exceptions triggered by the package limited to 2: — GuzzleHttp\Exception\ClientException (to assure any debugging can be done — Fruitware\WhmcsWrapper\Exception\RuntimeException (main exception handling any fatal errors) The package follows principles described in “The Pragmatic Programmer” by Andy Hunt. P.S. It can be considered a beta-release
1 parent 3684d15 commit c3c17f3

File tree

5 files changed

+199
-314
lines changed

5 files changed

+199
-314
lines changed

demo/index.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
/** @noinspection ALL */
3+
require_once '../vendor/autoload.php';
4+
5+
use Fruitware\WhmcsWrapper\Facade;
6+
7+
$apiUrl = 'https://example.com';
8+
$apiIdentifier = '';
9+
$apiSecret = '';
10+
11+
try {
12+
$client = Facade::run()->connect(
13+
$apiUrl,
14+
$apiIdentifier,
15+
$apiSecret
16+
);
17+
var_dump($client->call('GetClients'));
18+
} catch (Exception $exception) {
19+
var_dump('Error: ', $exception->getMessage(), $exception->getTraceAsString());
20+
}

src/Config/ConfigInterface.php

Lines changed: 38 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,107 +3,83 @@
33
namespace Fruitware\WhmcsWrapper\Config;
44

55
/**
6-
* @todo End uo with the configuration architecture
76
* @package Fruitware\WhmcsWrapper
7+
* @author Fruits Foundation <[email protected]>
88
*/
99
interface ConfigInterface
1010
{
1111
/**
12-
* Constructor expected to be protected but omitted to comply
13-
*
1412
* ConfigInterface constructor.
13+
* Protected to disable instancing but static i() method
14+
*
15+
*
1516
* @param string $apiBaseUri
16-
* @param string $apiIdentifier
17-
* @param string $apiSecret
17+
* @param string $key
18+
* @param string $secret
1819
* @param array $postDefaultParams
19-
* @param array $requestOptions
20+
* @param array $clientOptions
2021
*/
2122
public function __construct(
2223
string $apiBaseUri,
23-
string $apiIdentifier,
24-
string $apiSecret,
24+
string $key,
25+
string $secret,
2526
array $postDefaultParams,
26-
array $requestOptions
27+
array $clientOptions
2728
);
2829

2930
/**
30-
* Singleton config initialization
31-
*
32-
* @link https://developers.whmcs.com/api/authentication/
33-
*
3431
* @param string $baseUri path to your WHMCS installation (HTTP_ROOT)
35-
*
3632
* @param string $identifier WHMCS Identifier
3733
* @param string $secret WHMCS Identifier's Secret key
38-
*
39-
* Members are used as `form_fields` for each API-call as POST-request
4034
* @param array|string[] $defaultConfig default: array['responsetype' => 'json']
35+
* @param array $clientOptions Request options to apply. See \GuzzleHttp\RequestOptions
4136
*
42-
* @param array $requestOptions Request options to apply. See \GuzzleHttp\RequestOptions
4337
* @return ConfigInterface
4438
*/
4539
public static function i(
4640
string $baseUri,
4741
string $identifier,
4842
string $secret,
49-
array $defaultConfig = ['responsetype' => 'json'],
50-
array $requestOptions = ['timeout' => 3.0]
43+
array $defaultConfig = [],
44+
array $clientOptions = []
5145
):
5246
ConfigInterface;
5347

48+
public function getRequestUrl(): string;
49+
5450
/**
55-
* Transmitting securely default form_field POST-params to the Connector
56-
*
51+
* GuzzleHttp\ClientInterface client's config (used during initialization)
5752
* @return array
5853
*/
59-
public function getDefaultParams(): array;
54+
public function prepareConfig(): array;
6055

6156
/**
62-
* Transmitting securely API POST request url
57+
* Base64 encoded serialized array of custom field values
58+
* @link https://developers.whmcs.com/api-reference/addorder/
59+
* @link http://mahmudulruet.blogspot.com/2011/10/adding-and-posting-custom-field-values.html
6360
*
64-
* @return string
65-
*/
66-
public function getRequestUrl(): string;
67-
68-
/**
69-
* Transmitting given authorization `identifier` to configure http-client
61+
* 1. Login to your WHMCS admin panel.
62+
* 2. Navigate Setup->Client Custom Fields
63+
* 3. If there is no custom fields yet create a new one; say named "VAT".
64+
* 4. After creating the field, see the HTML source from the page by right clicking on page and click view source (in Firefox).
65+
* 5. Find the text "VAT".
66+
* 6. You will find something like this line of HTML code (<input type="text" size="30" value="VAT" name="fieldname[11]">)
67+
* 7. This fieldname[] with id may vary by users admin panel. So track the id from fieldname[11] and yes it's 11. If you find something like <input type="text" size="30" value="VAT" name="fieldname[xx]"> then 'xx' will be the id you have to use in your $customfields array. The array now should look like:
7068
*
71-
* @return string
72-
*/
73-
public function getAuthIdentifier(): string;
74-
75-
/**
76-
* Transmitting `base_uri` value to configure http-client
69+
* $customfields = [
70+
* "11" => "123456",
71+
* "12" => "678945"
72+
* ];
73+
* $postfields["customfields"] = base64_encode(serialize($customfields));
7774
*
78-
* @return string
79-
*/
80-
public function getBaseUri(): string;
81-
82-
/**
83-
* Transmitting given authorization `secret` to configure http-client
75+
* Preprocessing the request params.
76+
* Main purpose of the method is to encode `customfields` param.
8477
*
85-
* @return string
86-
*/
87-
public function getAuthSecret(): string;
88-
89-
/**
90-
* Setting default http-client options
78+
* @param string $action method name
79+
* @param array $params query params
80+
* @param bool $skipValidation cancel validation of the required fields
9181
*
9282
* @return array
9383
*/
94-
public function getRequestOptions(): array;
95-
96-
97-
/**
98-
* @param array $params
99-
* @return ConfigInterface
100-
*/
101-
public function updateDefaultParams(array $params = []): ConfigInterface;
102-
103-
104-
/**
105-
* @param array $options
106-
* @return ConfigInterface
107-
*/
108-
public function updateRequestOptions(array $options = []): ConfigInterface;
84+
public function prepareRequestOptions(string $action, array $params, bool $skipValidation): array;
10985
}

src/Config/DefaultConfig.php

Lines changed: 45 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -2,64 +2,49 @@
22

33
namespace Fruitware\WhmcsWrapper\Config;
44

5+
use function filter_var;
56
use function rtrim;
67

78
/**
89
* Class DefaultConfig
910
*
10-
* @package Fruitware\WhmcsWrapper\Config
11+
* @package Fruitware\WhmcsWrapper
12+
* @author Fruits Foundation <[email protected]>
1113
*/
1214
final class DefaultConfig implements ConfigInterface
1315
{
14-
/**
15-
* @var string
16-
*/
1716
protected string $apiRequestUrl = '/includes/api.php';
17+
protected string $key;
18+
protected string $secret;
1819

19-
/**
20-
* @var string
21-
*/
22-
protected string $apiBaseUri;
23-
24-
/**
25-
* @var string
26-
*/
27-
protected string $apiIdentifier;
28-
29-
/**
30-
* @var string
31-
*/
32-
protected string $apiSecret;
33-
34-
/**
35-
* @var array
36-
*/
37-
protected array $postDefaultParams;
20+
protected array $postDefaultParams = [
21+
'responsetype' => 'json'
22+
];
3823

39-
/**
40-
* @var array
41-
*/
42-
protected array $requestOptions;
24+
protected array $clientOptions = [
25+
'base_uri' => '',
26+
];
4327

4428
/**
4529
* @inheritDoc
4630
*/
47-
protected function __construct(
31+
public function __construct(
4832
string $apiBaseUri,
49-
string $apiIdentifier,
50-
string $apiSecret,
33+
string $key,
34+
string $secret,
5135
array $postDefaultParams,
52-
array $requestOptions
36+
array $clientOptions
5337
) {
54-
/**
55-
* Filtering trailing slash
56-
*/
57-
$this->apiBaseUri = rtrim($apiBaseUri, '/');
38+
$this->key = $key;
39+
$this->secret = $secret;
5840

59-
$this->apiIdentifier = $apiIdentifier;
60-
$this->apiSecret = $apiSecret;
61-
$this->postDefaultParams = $postDefaultParams;
62-
$this->requestOptions = $requestOptions;
41+
if ($postDefaultParams) {
42+
$this->postDefaultParams = $postDefaultParams;
43+
}
44+
if ($clientOptions) {
45+
$this->clientOptions = $clientOptions;
46+
}
47+
$this->clientOptions['base_uri'] = filter_var(rtrim($apiBaseUri, "/"), FILTER_SANITIZE_URL);
6348
}
6449

6550
/**
@@ -69,19 +54,18 @@ public static function i(
6954
string $baseUri,
7055
string $identifier,
7156
string $secret,
72-
array $defaultConfig = ['responsetype' => 'json'],
73-
array $requestOptions = ['timeout' => 3.0]
57+
array $defaultConfig = [],
58+
array $clientOptions = []
7459
): ConfigInterface {
7560
return new self(
7661
$baseUri,
7762
$identifier,
7863
$secret,
7964
$defaultConfig,
80-
$requestOptions
65+
$clientOptions
8166
);
8267
}
8368

84-
8569
/**
8670
* Transmitting securely API POST request url
8771
*
@@ -93,77 +77,34 @@ public function getRequestUrl(): string
9377
}
9478

9579
/**
96-
* Transmitting given authorization `identifier` to configure http-client
97-
*
98-
* @return string
99-
*/
100-
public function getAuthIdentifier(): string
101-
{
102-
return $this->apiIdentifier;
103-
}
104-
105-
106-
/**
107-
* Transmitting `base_uri` value to configure http-client
108-
*
109-
* @return string
110-
*/
111-
public function getBaseUri(): string
112-
{
113-
return $this->apiBaseUri;
114-
}
115-
116-
/**
117-
* @return string `secret` to configure http-client
118-
*/
119-
public function getAuthSecret(): string
120-
{
121-
return $this->apiSecret;
122-
}
123-
124-
/**
125-
* @return array default http-client options
80+
* @inheritDoc
12681
*/
127-
public function getRequestOptions(): array
82+
public function prepareConfig(): array
12883
{
129-
return $this->requestOptions;
84+
return $this->clientOptions;
13085
}
13186

13287
/**
133-
* @param array $options
134-
* @return ConfigInterface
88+
* @inheritDoc
13589
*/
136-
public function updateRequestOptions(array $options = []): ConfigInterface
90+
public function prepareRequestOptions(string $action, array $params, bool $skipValidation): array
13791
{
138-
if ($options) {
139-
$this->requestOptions = array_merge($this->requestOptions, $options);
92+
if ($skipValidation) {
93+
$params['skipvalidation'] = true;
14094
}
141-
return $this;
142-
}
95+
$params['action'] = $action;
14396

97+
$result = array_merge(
98+
$this->postDefaultParams, [
99+
'identifier' => $this->key,
100+
'secret' => $this->secret,
101+
], $params);
144102

145-
/**
146-
* @param array $params
147-
* @return ConfigInterface
148-
*/
149-
public function updateDefaultParams(array $params = []): ConfigInterface
150-
{
151-
if ($params) {
152-
$this->postDefaultParams = array_merge($this->postDefaultParams, $params);
103+
if (!empty($result['customfields'])) {
104+
$result['customfields'] = base64_encode(serialize($result['customfields']));
153105
}
154-
return $this;
155-
}
156-
157-
/**
158-
* Transmitting securely default form_field POST-params to the Connector
159-
*
160-
* @return array
161-
*/
162-
public function getDefaultParams(): array
163-
{
164-
return $this->postDefaultParams + [
165-
'identifier' => $this->apiIdentifier,
166-
'secret' => $this->apiSecret,
167-
];
106+
return [
107+
'form_params' => $result
108+
];
168109
}
169110
}

0 commit comments

Comments
 (0)