Skip to content

Commit

Permalink
PHP SDK 업데이트 (#7)
Browse files Browse the repository at this point in the history
* chore: Apply formatting (#5)

* chore: Apply formatting to files that was obmitted

* feat: Refactor project file tree

* [feat] Add send request method and items Request class (#10)

* test: Add test code for Single ItemAdd

* feat: Add uuid generator to test-utils

* test: Add failing Request class test

* test: Add failing test for ItemRequest class

* feat: Add ItemRequest and Item class

* chore: Remove unecessary comment

[Why]
SVC 에서 알아서 누가 어느줄을 작성했는지 보여주기 때문에 (git blame) 불필요한 boilerplate임

* test: Add default items payload generator

Added a utility function to TestUtils

* test: Add failing test for AddItemTest

* feat: Add AddItem class

* test: Add failing test for Zaiclient sendRequest

* chore: Change snake cased method names

* test: Add failing test for sendRequest method

* feat: Add sendRequest method to ZaiClient

* [feat] Add UpdateItem, DeleteItem and Events (#11)

* test: Add failing test for delete and update item

* test: Add validation testing in AddItemTest

* feat: Add UpdateItem and DeleteItem class

Validation to the constructor of these classes is not
necessary. It is done when creating the Item class for
the request payload.

* refac: Remove call_type header

The Collector API no longer needs this header.

* test: Add failing test for Event Request

* feat: Add EventRequest Class

* test: Add failing test for Event Request

* feat: Add Event class

* feat: Implement EventRequest further to pass tests

Previously there were tests that didn't pass.
Because it wasn't able to get the payloads

* [feat] Add all events, recommendation request with test codes (#12)

* refac: Add more error logs to validation

* test: Add failing test for Recommendation

* feat: Add isAssoc function to utility function

* feat: Add Recommendation Request

* feat: Add GetUserRecommendation

* feat: Add GetRelatedRecommendation, GetRerankingRecommendation

* refac: Create a folder tree for Request tests

* feat: Add ProductDetailView Request class

* feat: Add PurchaseEvent class

* refac: Rename isAssoc fn to isAssociativeArray

* feat: Add AddpurchaseEvent class

* feat: Add AddRateEvent class

* feat: Add Other Event classes

* feat: Fix errors due to change in Validator

* fix: Fix error when setting time_to_live

* [feat] Fix minor errors (#13)

* fix: Fix minor errors

* feat: Add integration test and reorder file tree

* fix: Add Item mapper

* fix: Fix error in item requests

* fix: Delete all unecessary files

* chore: Add phpunit.xml

* refac: Rename isZaiRec param for PageViewEvent

* chore: Fix the sonarlint errors

* refac: Change EventResponse class name to EventLoggerResponse

* feat: Fix minor typos and unecessary variables
  • Loading branch information
eomiso authored Aug 18, 2023
1 parent e56bf67 commit 2f83258
Show file tree
Hide file tree
Showing 86 changed files with 5,509 additions and 2,675 deletions.
8 changes: 8 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[*]
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
end_of_line = lf
indent_style = space
charset = utf-8
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/vendor/
/example/
*.lock
*.lock

.phpunit.result.cache
8 changes: 8 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"recommendations": [
"devsense.profiler-php-vscode",
"devsense.phptools-vscode",
"editorconfig.editorconfig",
"devsense.composer-php-vscode"
]
}
20 changes: 20 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"files.exclude": {
"**/.git": false,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true
},
"[php]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "DEVSENSE.phptools-vscode",
},
"files.associations": {
"vendor/**/*": "vendor"
},
"[vendor]": {
"editor.formatOnSave": false
}
}
14 changes: 10 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
{
"name": "zaikorea/zaiclient",
"version": "2.2.1",
"version": "3.0.0",
"description": "Z.Ai official client SDK",
"hompage": "https://www.zaikorea.org",
"autoload": {
"psr-4": {
"ZaiKorea\\": "src/"
"ZaiClient\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"ZaiClient\\Tests\\": "tests/"
}
},
"authors": [
Expand All @@ -15,10 +20,11 @@
],
"require": {
"guzzlehttp/guzzle": "~6.0|~7.0",
"netresearch/jsonmapper": "~3.0|~4.0"
"netresearch/jsonmapper": "~3.0|~4.0",
"ramsey/uuid": "~3.0|~4.0"
},
"require-dev": {
"phpunit/phpunit": "~6.0|~7.0|~8.0|~9.0"
"phpunit/phpunit": "~6.0|~7.0|~8.0"
},
"config": {
"allow-plugins": {
Expand Down
9 changes: 9 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit bootstrap="tests/bootstrap.php">
<testsuites>
<testsuite name="My Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
</phpunit>
35 changes: 35 additions & 0 deletions src/Configs/Config.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

/**
* Config
* @author Uiseop Eom <[email protected]>
* @modifiedBy <name>
*/

namespace ZaiClient\Configs;

class Config
{
const COLLECTOR_API_ENDPOINT = "https://collector-api%s.zaikorea.org";

const EVENTS_API_PATH = '/events';
const ITEMS_API_PATH = '/items';

const ML_API_ENDPOINT = "https://ml-api%s.zaikorea.org";
const ML_API_PATH_PREFIX = '/clients/%s/recommenders';

const USER_RECOMMENDATION_PATH = '/user-recommendations';
const RELATED_ITEMS_PATH = "/related-items";

const RERANKING_RECOMMENDATION_PATH = "/reranking";

const HMAC_ALGORITHM = 'sha256';
const HMAC_SCHEME = 'ZAi';
const ZAI_CLIENT_ID_HEADER = 'X-ZAI-CLIENT-ID';
const ZAI_UNIX_TIMESTAMP_HEADER = 'X-ZAI-TIMESTAMP';
const ZAI_AUTHORIZATION_HEADER = 'X-ZAI-AUTHORIZATION';
const BATCH_REQUEST_CAP = '50';
const EPSILON = 1e-4;

const TEST_EVENT_TIME_TO_LIVE = 60 * 60 * 24; // 1 day
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
* @modifiedBy <name>
*/

namespace ZaiKorea\ZaiClient\Exceptions;
namespace ZaiClient\Exceptions;

use \GuzzleHttp\Exception\BadResponseException;

/**
*
*
*/
class BatchSizeLimitExceededException extends \Exception
{
Expand All @@ -21,11 +21,6 @@ public function __construct($records_num)
parent::__construct($message, 2);
}

public function getHttpStatusCode()
{
return $this->http_status_code;
}

public function __toString()
{
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
Expand Down
26 changes: 26 additions & 0 deletions src/Exceptions/EmptyBatchException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

/**
* BatchSizeLimitExceededException
* @author Uiseop Eom <[email protected]>
* @modifiedBy <name>
*/

namespace ZaiClient\Exceptions;

/**
*
*/
class EmptyBatchException extends \Exception
{
public function __construct()
{
$message = sprintf("Number of total records cannot be 0");
parent::__construct($message, 2);
}

public function __toString()
{
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
* @modifiedBy <name>
*/

namespace ZaiKorea\ZaiClient\Exceptions;
namespace ZaiClient\Exceptions;

use \GuzzleHttp\Exception\RequestException;

/**
* Exception class thrown when the connection succeeded but
* Exception class thrown when the connection succeeded but
* request failed due to client or server error.
*/
class ZaiClientException extends \Exception
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* @modifiedBy <name>
*/

namespace ZaiKorea\ZaiClient\Exceptions;
namespace ZaiClient\Exceptions;

use \GuzzleHttp\Exception\TransferException;

Expand Down
52 changes: 52 additions & 0 deletions src/Requests/Events/AddCartaddEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php
namespace ZaiClient\Requests\Events;

use InvalidArgumentException;

use ZaiClient\Requests\Events\EventRequest;

class AddCartaddEvent extends EventRequest
{
const DEFAULT_EVENT_TYPE = "cartadd";
const DEFAULT_EVENT_VALUE = "null";

/**
* @param string $user_id
* @param string $item_id
* @param array $request_options
*/
public function __construct(
$user_id,
$item_id,
$request_options = []
) {
$this->validate($item_id);

parent::__construct(
$user_id,
[$item_id],
(array_key_exists("timestamp", $request_options)
? $request_options["timestamp"]
: null),
self::DEFAULT_EVENT_TYPE,
[self::DEFAULT_EVENT_VALUE],
(array_key_exists("from", $request_options)
? [$request_options["from"]]
: [null]),
(array_key_exists("is_zai_rec", $request_options)
? [$request_options["is_zai_rec"]]
: [false])
);
}

private function validate($item_id)
{
if (!$item_id) {
throw new InvalidArgumentException("item_id is required");
}

if (!is_string($item_id)) {
throw new InvalidArgumentException("item_id must be a string");
}
}
}
94 changes: 94 additions & 0 deletions src/Requests/Events/AddCustomEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php
namespace ZaiClient\Requests\Events;

use InvalidArgumentException;

use ZaiClient\Requests\Events\EventRequest;
use ZaiClient\Utils\Util;

class AddCustomEvent extends EventRequest
{
/**
* @param string $user_id
* @param string $custom_event_type
* @param array $custom_actions
* @param array $request_options
*/
public function __construct(
$user_id,
$custom_event_type,
$custom_actions,
$request_options = []
) {
if (!$custom_actions) {
throw new InvalidArgumentException("custom_actions is required");
}

if (!is_array($custom_actions)) {
throw new InvalidArgumentException("custom_actions must be an array");
}

// change to 2D array if $custom_actions is 1D array (custom_actions on single item)
// [item_id => "P001", value =>"watch"] to [[item_id => "P001", value =>"watch"]]
if (gettype(reset($custom_actions)) != "array") {
$custom_actions = array($custom_actions);
}

// Validate if $custom_actions is sequential array
if (!Util::isSequentialArray($custom_actions)) {
throw new InvalidArgumentException("custom_actions must be a sequential array");
}

$flattenedCustomActions = $this->flattenCustomActions($custom_actions);

parent::__construct(
$user_id,
array_map(function ($custom_action) {
return $custom_action["item_id"];
}, $flattenedCustomActions),
(array_key_exists("timestamp", $request_options)
? $request_options["timestamp"]
: null),
$custom_event_type,
array_map(function ($custom_action) {
return $custom_action["value"];
}, $flattenedCustomActions),
array_fill(0, count($flattenedCustomActions), null),
array_map(function ($custom_action) {
return $custom_action["is_zai_rec"];
}, $flattenedCustomActions)
);
}

/**
* @param array $custom_actions
* @return array
*/
private function flattenCustomActions($custom_actions)
{
$flattenOrders = [];

foreach ($custom_actions as $action) {
if (!array_key_exists("item_id", $action)) {
throw new InvalidArgumentException("item_id is required");
}

if (!array_key_exists("item_id", $action)) {
throw new InvalidArgumentException("value is required");
}

$flattenOrders[] = [
"item_id" => $action["item_id"],
"value" => $action["value"],
"is_zai_rec" => (array_key_exists("is_zai_rec", $action)
? $action["is_zai_rec"]
: false),
"from" => (array_key_exists("from", $action)
? $action["from"]
: null)
];
}

return $flattenOrders;
}
}
Loading

0 comments on commit 2f83258

Please sign in to comment.