From 751ec73273a2218d9561ae1e129716785f87a429 Mon Sep 17 00:00:00 2001 From: Steven Wade Date: Mon, 15 Feb 2016 17:00:10 -0500 Subject: [PATCH 1/5] Add support for custom fields returned via a mailbox or conversation - Created reference models for custom fields - Created a factory class to create and map custom fields when returned from a mailbox or conversation --- src/HelpScout/CustomFieldFactory.php | 74 ++++++++++++++++++ .../descriptions/reports/conversations.php | 2 +- src/HelpScout/model/Conversation.php | 45 +++++++++++ src/HelpScout/model/Mailbox.php | 19 +++++ .../customfields/AbstractCustomFieldRef.php | 78 +++++++++++++++++++ .../model/ref/customfields/DateFieldRef.php | 11 +++ .../ref/customfields/DropdownFieldRef.php | 11 +++ .../ref/customfields/MultiLineFieldRef.php | 11 +++ .../model/ref/customfields/NumberFieldRef.php | 11 +++ .../ref/customfields/SingleLineFieldRef.php | 11 +++ 10 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 src/HelpScout/CustomFieldFactory.php create mode 100644 src/HelpScout/model/ref/customfields/AbstractCustomFieldRef.php create mode 100644 src/HelpScout/model/ref/customfields/DateFieldRef.php create mode 100644 src/HelpScout/model/ref/customfields/DropdownFieldRef.php create mode 100644 src/HelpScout/model/ref/customfields/MultiLineFieldRef.php create mode 100644 src/HelpScout/model/ref/customfields/NumberFieldRef.php create mode 100644 src/HelpScout/model/ref/customfields/SingleLineFieldRef.php diff --git a/src/HelpScout/CustomFieldFactory.php b/src/HelpScout/CustomFieldFactory.php new file mode 100644 index 00000000..ec5264d7 --- /dev/null +++ b/src/HelpScout/CustomFieldFactory.php @@ -0,0 +1,74 @@ + 'name' + ); + + return static::createField( + $attributes['fieldType'], + static::mapAttributes($attributes, $map) + ); + } + + public static function fromConversation(array $attributes) + { + $map = array( + 'fieldId' => 'id' + ); + + return static::createField( + $attributes['type'], + static::mapAttributes($attributes, $map) + ); + } + + public static function createField($type, array $attributes) + { + $attributes = (object) $attributes; + switch ($type) { + case 'SINGLE_LINE' : + return new SingleLineFieldRef($attributes); + break; + case 'MULTI_LINE' : + return new MultiLineFieldRef($attributes); + break; + case 'DROPDOWN' : + return new DropdownFieldRef($attributes); + break; + case 'DATE' : + return new DateFieldRef($attributes); + break; + case 'NUMBER' : + return new NumberFieldRef($attributes); + break; + } + + throw new \InvalidArgumentException($type . ' is not a supported Custom Field type.'); + } + + protected static function mapAttributes(array $attributes, array $map) + { + $temp = array(); + + foreach ($attributes as $key => $value) { + if (array_key_exists($key, $map)) { + $temp[$map[$key]] = $value; + } else { + $temp[$key] = $value; + } + } + + return $temp; + } +} diff --git a/src/HelpScout/descriptions/reports/conversations.php b/src/HelpScout/descriptions/reports/conversations.php index 3ee42edf..32fa1e69 100644 --- a/src/HelpScout/descriptions/reports/conversations.php +++ b/src/HelpScout/descriptions/reports/conversations.php @@ -133,7 +133,7 @@ 'getConversationsDrillDownByFieldReport' => array( 'httpMethod' => 'GET', - 'uri' => 'reports/conversations/fields-drilldown.json', + 'uri' => 'reports/conversations/customfields-drilldown.json', 'parameters' => array( 'start' => array( 'location' => 'query', diff --git a/src/HelpScout/model/Conversation.php b/src/HelpScout/model/Conversation.php index 700f3477..1202ef8e 100644 --- a/src/HelpScout/model/Conversation.php +++ b/src/HelpScout/model/Conversation.php @@ -1,6 +1,8 @@ customFields)) { + $this->customFields = array(); + + foreach ($data->customFields as $field) { + $this->customFields[] = CustomFieldFactory::fromConversation((array) $field); + } + } } } @@ -154,6 +165,8 @@ public function getObjectVars() { } $this->addThreadsToVars($vars); + $this->addCustomFieldsToVars($vars); + return $vars; } @@ -170,6 +183,22 @@ private function addThreadsToVars(array &$vars) { $vars['threads'] = $threads; } + private function addCustomFieldsToVars(array &$vars) { + /* @var $field \HelpScout\model\ref\customfields\AbstractCustomFieldRef */ + $fields = array(); + + if ($list = $this->getCustomFields()) { + foreach ($list as $field) { + $fields[] = array( + 'fieldId' => $field->getId(), + 'name' => $field->getName(), + 'value' => $field->getValue() + ); + } + } + $vars['customFields'] = $fields; + } + public function toJSON() { $vars = $this->getObjectVars(); return json_encode($vars); @@ -570,4 +599,20 @@ public function getThreads($cache = true, $apiCall = true) { } return $this->threads; } + + /** + * @return array|null + */ + public function getCustomFields() + { + return $this->customFields; + } + + /** + * @param array|null $customFields + */ + public function setCustomFields(array $customFields) + { + $this->customFields = $customFields; + } } diff --git a/src/HelpScout/model/Mailbox.php b/src/HelpScout/model/Mailbox.php index 0b62bf04..0f0f051f 100644 --- a/src/HelpScout/model/Mailbox.php +++ b/src/HelpScout/model/Mailbox.php @@ -1,6 +1,8 @@ id = isset($data->id) ? $data->id : null; @@ -19,6 +23,13 @@ public function __construct($data=null) { $this->email = isset($data->email) ? $data->email : null; $this->createdAt = isset($data->createdAt) ? $data->createdAt : null; $this->modifiedAt = isset($data->modifiedAt) ? $data->modifiedAt : null; + + if (isset($data->customFields)) { + + foreach ($data->customFields as $field) { + $this->customFields[] = CustomFieldFactory::fromMailbox((array) $field); + } + } } } @@ -193,4 +204,12 @@ public function toRef() { return $ref; } + + /** + * @return array + */ + public function getCustomFields() + { + return $this->customFields; + } } diff --git a/src/HelpScout/model/ref/customfields/AbstractCustomFieldRef.php b/src/HelpScout/model/ref/customfields/AbstractCustomFieldRef.php new file mode 100644 index 00000000..7b756647 --- /dev/null +++ b/src/HelpScout/model/ref/customfields/AbstractCustomFieldRef.php @@ -0,0 +1,78 @@ +id = isset($data->id) ? $data->id : null; + $this->name = isset($data->name) ? $data->name : null; + $this->value = isset($data->value) ? $data->value : null; + $this->type = isset($data->type) ? $data->type : null; + $this->options = isset($data->options) ? $data->options : null; + } + } + + abstract public function validate(); + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @return mixed + */ + public function getValue() + { + return $this->value; + } + + /** + * @param mixed $value + */ + public function setValue($value) + { + $this->value = $value; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } +} diff --git a/src/HelpScout/model/ref/customfields/DateFieldRef.php b/src/HelpScout/model/ref/customfields/DateFieldRef.php new file mode 100644 index 00000000..34a5b87a --- /dev/null +++ b/src/HelpScout/model/ref/customfields/DateFieldRef.php @@ -0,0 +1,11 @@ + Date: Wed, 17 Feb 2016 08:58:05 -0500 Subject: [PATCH 2/5] Add validation for custom field responses --- src/HelpScout/ValidationException.php | 7 ++++ .../customfields/AbstractCustomFieldRef.php | 16 +++++--- .../model/ref/customfields/DateFieldRef.php | 36 ++++++++++++++++- .../ref/customfields/DropdownFieldRef.php | 24 +++++++++++- .../ref/customfields/MultiLineFieldRef.php | 9 ++++- .../model/ref/customfields/NumberFieldRef.php | 8 +++- .../ref/customfields/SingleLineFieldRef.php | 9 ++++- tests/customfields/DateFieldRefTest.php | 27 +++++++++++++ tests/customfields/DropdownFieldRefTest.php | 39 +++++++++++++++++++ tests/customfields/MultiLineFieldRefTest.php | 16 ++++++++ tests/customfields/NumberFieldRefTest.php | 16 ++++++++ tests/customfields/SingleLineFieldRefTest.php | 16 ++++++++ 12 files changed, 208 insertions(+), 15 deletions(-) create mode 100644 src/HelpScout/ValidationException.php create mode 100644 tests/customfields/DateFieldRefTest.php create mode 100644 tests/customfields/DropdownFieldRefTest.php create mode 100644 tests/customfields/MultiLineFieldRefTest.php create mode 100644 tests/customfields/NumberFieldRefTest.php create mode 100644 tests/customfields/SingleLineFieldRefTest.php diff --git a/src/HelpScout/ValidationException.php b/src/HelpScout/ValidationException.php new file mode 100644 index 00000000..069556f2 --- /dev/null +++ b/src/HelpScout/ValidationException.php @@ -0,0 +1,7 @@ +validate($value); $this->value = $value; } diff --git a/src/HelpScout/model/ref/customfields/DateFieldRef.php b/src/HelpScout/model/ref/customfields/DateFieldRef.php index 34a5b87a..96bc5512 100644 --- a/src/HelpScout/model/ref/customfields/DateFieldRef.php +++ b/src/HelpScout/model/ref/customfields/DateFieldRef.php @@ -1,11 +1,43 @@ options; + } + + public function setOptions(array $options) + { + $this->options = $options; + } + + public function validate($value) + { + $optionIds = array(); + + foreach ($this->getOptions() as $option) { + $optionIds[] = $option['id']; + } + + if (!in_array($value, $optionIds)) { + throw new ValidationException('The dropdown value must be the ID of one of the options'); + } } } diff --git a/src/HelpScout/model/ref/customfields/MultiLineFieldRef.php b/src/HelpScout/model/ref/customfields/MultiLineFieldRef.php index 5854759f..fae54ece 100644 --- a/src/HelpScout/model/ref/customfields/MultiLineFieldRef.php +++ b/src/HelpScout/model/ref/customfields/MultiLineFieldRef.php @@ -1,11 +1,16 @@ self::LIMIT) { + throw new ValidationException('Multi line responses must be less than ' . self::LIMIT . ' characters long'); + } } } diff --git a/src/HelpScout/model/ref/customfields/NumberFieldRef.php b/src/HelpScout/model/ref/customfields/NumberFieldRef.php index e76ca1a0..a72b0049 100644 --- a/src/HelpScout/model/ref/customfields/NumberFieldRef.php +++ b/src/HelpScout/model/ref/customfields/NumberFieldRef.php @@ -1,11 +1,15 @@ self::LIMIT) { + throw new ValidationException('Single line responses must be less than ' . self::LIMIT . ' characters long'); + } } } diff --git a/tests/customfields/DateFieldRefTest.php b/tests/customfields/DateFieldRefTest.php new file mode 100644 index 00000000..66609937 --- /dev/null +++ b/tests/customfields/DateFieldRefTest.php @@ -0,0 +1,27 @@ +setValue('12-25-2015'); + } + + /** + * @group customfields + */ + public function testValidationPassesWhenValueIsAnOptionId() + { + $field = new DateFieldRef; + $field->setValue('2015-12-25'); + + $this->assertTrue(true); + } +} diff --git a/tests/customfields/DropdownFieldRefTest.php b/tests/customfields/DropdownFieldRefTest.php new file mode 100644 index 00000000..d022e08c --- /dev/null +++ b/tests/customfields/DropdownFieldRefTest.php @@ -0,0 +1,39 @@ +getField(); + $field->setValue(18); + } + + /** + * @group customfields + */ + public function testValidationPassesWhenValueIsAnOptionId() + { + $field = $this->getField(); + $field->setValue(12); + + $this->assertTrue(true); + } + + private function getField() + { + $field = new DropdownFieldRef; + $field->setOptions(array( + array('id' => 12, 'label' => 'Blue', 'order' => 1), + array('id' => 3, 'label' => 'Red', 'order' => 2), + array('id' => 6, 'label' => 'Green', 'order' => 3) + )); + + return $field; + } +} diff --git a/tests/customfields/MultiLineFieldRefTest.php b/tests/customfields/MultiLineFieldRefTest.php new file mode 100644 index 00000000..64ed6ca8 --- /dev/null +++ b/tests/customfields/MultiLineFieldRefTest.php @@ -0,0 +1,16 @@ +setValue(str_repeat('s', MultiLineFieldRef::LIMIT + 1)); + } +} diff --git a/tests/customfields/NumberFieldRefTest.php b/tests/customfields/NumberFieldRefTest.php new file mode 100644 index 00000000..88bcfd13 --- /dev/null +++ b/tests/customfields/NumberFieldRefTest.php @@ -0,0 +1,16 @@ +setValue('foo'); + } +} diff --git a/tests/customfields/SingleLineFieldRefTest.php b/tests/customfields/SingleLineFieldRefTest.php new file mode 100644 index 00000000..fabd6856 --- /dev/null +++ b/tests/customfields/SingleLineFieldRefTest.php @@ -0,0 +1,16 @@ +setValue(str_repeat('s', SingleLineFieldRef::LIMIT + 1)); + } +} From f94e4c050c90588c6cc1b9e8f3489b674b374cad Mon Sep 17 00:00:00 2001 From: Steven Wade Date: Wed, 17 Feb 2016 09:39:16 -0500 Subject: [PATCH 3/5] Fix syntax issues for PHP 5.3 and 5.4 --- src/HelpScout/model/ref/customfields/DateFieldRef.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/HelpScout/model/ref/customfields/DateFieldRef.php b/src/HelpScout/model/ref/customfields/DateFieldRef.php index 96bc5512..9c897a8a 100644 --- a/src/HelpScout/model/ref/customfields/DateFieldRef.php +++ b/src/HelpScout/model/ref/customfields/DateFieldRef.php @@ -9,17 +9,18 @@ class DateFieldRef extends AbstractCustomFieldRef public function validate($value) { $didError = false; - $matches = []; + $matches = array(); if ($value !== '') { if (! (bool) preg_match('/\d{4}-\d{2}-\d{2}/', $value, $matches)) { $didError = true; } else { // Grab the date string from the date value, if anything is left (timestamp or time zone) // count it as an error. - if (isset($matches[0]) - && ! empty(trim(str_replace($matches[0], '', $value))) - ) { - $didError = true; + if (isset($matches[0])) { + $trimmed = trim(str_replace($matches[0], '', $value)); + if (! empty($trimmed)) { + $didError = true; + } } if (!$didError) { $millis = strtotime($value); From 16090817bdae195b778933b149e86b5c4176d3b5 Mon Sep 17 00:00:00 2001 From: Steven Wade Date: Wed, 17 Feb 2016 14:36:39 -0500 Subject: [PATCH 4/5] Fix issue where a null response body in `checkStatus` would trigger a type violation on `getErrorMessage` --- src/HelpScout/ApiClient.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/HelpScout/ApiClient.php b/src/HelpScout/ApiClient.php index 587e2792..c0eab9cd 100644 --- a/src/HelpScout/ApiClient.php +++ b/src/HelpScout/ApiClient.php @@ -718,6 +718,7 @@ private function getItem($url, $params, $method, $model) { */ private function checkStatus($statusCode, $type, $expected = 200, $responseBody = array()) { $expected = (array) $expected; + $responseBody = $responseBody ?: array(); if (!in_array($statusCode, $expected)) { $exception = new ApiException( From 95764ad18add1001224bef79929a47cd739c47d8 Mon Sep 17 00:00:00 2001 From: Steven Wade Date: Fri, 19 Feb 2016 14:45:11 -0500 Subject: [PATCH 5/5] Updated README and CHANGELOG for the 1.8.0 release --- CHANGELOG.md | 4 +++ README.md | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0597c6b9..8761851e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +#### 1.8.0 (February 19, 2016) +* Added support for Custom Fields returned within a Mailbox details +* Added support for Custom Field Responses returned with a Conversation + #### 1.7.0 (February 2, 2016) * Deprecated "Team" reports. With the arrival of "Teams" with the new Plus Plan, the previous "Team" report has been renamed "Company" report * Added new reports methods: `getCompanyReport`, `getCustomersHelpedCompanyReport`, `getCompanyDrillDownReport` diff --git a/README.md b/README.md index 37d05ab3..b27b6887 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Help Scout PHP Wrapper [![Build Status](https://travis-ci.org/helpscout/helpscou ================================================================================ > PHP Wrapper for the Help Scout API and Webhooks implementation. More information on our [developer site](http://developer.helpscout.net). -Version 1.7.0 Released +Version 1.8.0 Released --------------------- Please see the [Changelog](https://github.com/helpscout/helpscout-api-php/blob/master/CHANGELOG.md) for details. @@ -244,6 +244,91 @@ if ($webhook->isValid()) { } ``` +Example Usage: Custom Fields +------------------------ + +### Retrieving custom fields for a mailbox + +```php +include 'HelpScout/ApiClient.php'; + +use HelpScout\ApiClient; + +$scout = ApiClient::getInstance(); +$scout->setKey('your-api-key-here'); + +$mailbox = $scout->getMailbox(1234); +$customFields = $mailbox->getCustomFields(); +``` + +### Retrieving custom fields with responses for a conversation + +```php +$conversation = $scout->getConversation(1234); +$customFields = $conversation->getCustomFields(); + +``` + +### Filling in a value for a field on a conversation that hasn't been filled out yet + +This is if the conversation hasn't had **any** fields filled out yet + +```php +$conversation = $scout->getConversation(1234); +$mailbox = $scout->getMailbox($conversation->getMailbox()->getId()); + +$conversationFields = []; + +foreach ($mailbox->getCustomFields() as $customField) { + if ($customField->getId() == 88) { + $field = clone $customField; + $field->setValue('Foo'); + $conversationFields[] = $field; + } +} + +$conversation->setCustomFields($conversationFields); + +$scout->updateConversation($conversation); +``` + +### Updating a value for a field on a conversation + +```php +$conversation = $scout->getConversation(1234); + +foreach ($conversation->getCustomFields() as $customField) { + if ($customField->getId() == 88) { + $field->setValue('Bar'); + } +} + +$scout->updateConversation($conversation); +``` + +### Custom Field Validation + +#### Date Fields (`DateFieldRef`) + +Must be a valid date in the format of YYYY-MM-DD (year-month-day). + +#### Dropdown Fields (`DropdownFieldRef`) + +The value must be the ID of one of the available dropdown options. + +#### Multi Line Fields (`MultiLineFieldRef`) + +The maximum string length for a multi line value is 15000 characters. + +#### Number Fields (`NumberFieldRef`) + +Number values must be numeric. Integers and Decimals (floats) are allowed (ex: 100 or 12.34). + +#### Single Line Fields (`SingleLineFieldRef`) + +The maximum string length for a single line value is 255 characters. + + Debugging ------------------------ @@ -285,7 +370,6 @@ try { That outputs ```php -Input could not be validated Array ( [0] => Array