diff --git a/src/ApiConnectors/ArticleApiConnector.php b/src/ApiConnectors/ArticleApiConnector.php index b825dbaa..fd2c23a7 100644 --- a/src/ApiConnectors/ArticleApiConnector.php +++ b/src/ApiConnectors/ArticleApiConnector.php @@ -37,7 +37,7 @@ public function get(string $code, Office $office): Article // Make a request to read a single Article. Set the required values $request_article = new Request\Read\Article(); $request_article - ->setOffice($office->getCode()) + ->setOffice($office) ->setCode($code); // Send the Request document and set the response to this instance. diff --git a/src/ApiConnectors/BaseApiConnector.php b/src/ApiConnectors/BaseApiConnector.php index fa33353b..c007426a 100644 --- a/src/ApiConnectors/BaseApiConnector.php +++ b/src/ApiConnectors/BaseApiConnector.php @@ -47,6 +47,17 @@ public function __construct(AuthenticatedConnection $connection) $this->connection = $connection; } + /** + * Will return the current connection + * + * @return \PhpTwinfield\Secure\AuthenticatedConnection + * @throws Exception + */ + public function getConnection(): AuthenticatedConnection + { + return $this->connection; + } + /** * @see sendXmlDocument() * @throws Exception @@ -161,4 +172,72 @@ protected function getFinderService(): FinderService { return $this->connection->getAuthenticatedClient(Services::FINDER()); } -} + + /** + * Convert options array to an ArrayOfString which is accepted by Twinfield. + * + * In some cases you are not allowed to change certain options (such as the dimtype, which should always be DEB when using CustomerApiConnector->ListAll()), + * in which case the $forcedOptions parameter will be set by the ApiConnector for this option, which will override any user settings in $options + * + * @param array $options + * @param array $forcedOptions + * @return array + * @throws Exception + */ + public function convertOptionsToArrayOfString(array $options, array $forcedOptions = []): array { + if (isset($options['ArrayOfString'])) { + return $options; + } + + $optionsArrayOfString = ['ArrayOfString' => []]; + + foreach ($forcedOptions as $key => $value) { + unset($options[$key]); + $optionsArrayOfString['ArrayOfString'][] = array($key, $value); + } + + foreach ($options as $key => $value) { + $optionsArrayOfString['ArrayOfString'][] = array($key, $value); + } + + return $optionsArrayOfString; + } + + /** + * Map the response of a listAll to an array of the requested class + * + * Is used by child ApiConnectors to map a $data object received by the FinderService to one or more new entities of $objectClass + * using the methods and attributes in $methodToAttributeMap. Returns an array of $objectClass objects + * + * @param string $objectClass + * @param $data + * @param array $methodToAttributeMap + * @return array + * @throws Exception + */ + public function mapListAll(string $objectClass, $data, array $methodToAttributeMap): array { + if ($data->TotalRows == 0) { + return []; + } + + $objects = []; + + foreach ($data->Items->ArrayOfString as $responseArrayElement) { + $object = new $objectClass(); + + if (isset($responseArrayElement->string[0])) { + $elementArray = $responseArrayElement->string; + } else { + $elementArray = $responseArrayElement; + } + + foreach ($methodToAttributeMap as $key => $method) { + $object->$method($elementArray[$key]); + } + + $objects[] = $object; + } + + return $objects; + } +} \ No newline at end of file diff --git a/src/ApiConnectors/CustomerApiConnector.php b/src/ApiConnectors/CustomerApiConnector.php index 0f42276d..a8cf5acb 100644 --- a/src/ApiConnectors/CustomerApiConnector.php +++ b/src/ApiConnectors/CustomerApiConnector.php @@ -37,7 +37,7 @@ public function get(string $code, Office $office): Customer // Make a request to read a single customer. Set the required values $request_customer = new Request\Read\Customer(); $request_customer - ->setOffice($office->getCode()) + ->setOffice($office) ->setCode($code); // Send the Request document and set the response to this instance. diff --git a/src/ApiConnectors/InvoiceApiConnector.php b/src/ApiConnectors/InvoiceApiConnector.php index 3c9a6219..25806680 100644 --- a/src/ApiConnectors/InvoiceApiConnector.php +++ b/src/ApiConnectors/InvoiceApiConnector.php @@ -40,7 +40,7 @@ public function get(string $code, string $invoiceNumber, Office $office) $request_invoice ->setCode($code) ->setNumber($invoiceNumber) - ->setOffice($office->getCode()); + ->setOffice($office); // Send the Request document and set the response to this instance $response = $this->sendXmlDocument($request_invoice); diff --git a/src/ApiConnectors/SupplierApiConnector.php b/src/ApiConnectors/SupplierApiConnector.php index f6e692ee..5dd86365 100644 --- a/src/ApiConnectors/SupplierApiConnector.php +++ b/src/ApiConnectors/SupplierApiConnector.php @@ -37,7 +37,7 @@ public function get($code, Office $office): Supplier // Make a request to read a single customer. Set the required values $request_customer = new Request\Read\Supplier(); $request_customer - ->setOffice($office->getCode()) + ->setOffice($office) ->setCode($code); $response = $this->sendXmlDocument($request_customer); diff --git a/src/BaseObject.php b/src/BaseObject.php index d7db7e72..424be098 100644 --- a/src/BaseObject.php +++ b/src/BaseObject.php @@ -9,7 +9,7 @@ * * @author Jop peters */ -abstract class BaseObject +abstract class BaseObject implements HasMessageInterface { private $result; private $messages; @@ -31,12 +31,11 @@ public function getMessages() return $this->messages; } - public function addMessage(Message $message) + public function addMessage(Message $message): void { $this->messages[] = $message; - - return $this; } + public function setMessages($messages) { $this->messages = $messages; diff --git a/src/DomDocuments/BaseDocument.php b/src/DomDocuments/BaseDocument.php index ed9cb33b..2072bb78 100644 --- a/src/DomDocuments/BaseDocument.php +++ b/src/DomDocuments/BaseDocument.php @@ -3,6 +3,7 @@ namespace PhpTwinfield\DomDocuments; use PhpTwinfield\Enums\PerformanceType; +use PhpTwinfield\HasMessageInterface; use PhpTwinfield\Office; use PhpTwinfield\Transactions\TransactionFields\FreeTextFields; use PhpTwinfield\Transactions\TransactionFields\StartAndCloseValueFields; @@ -156,13 +157,24 @@ protected function appendPerformanceTypeFields(\DOMElement $element, $object): v * Use this instead of createElement(). * * @param string $tag - * @param string $textContent + * @param string|null $textContent + * @param HasMessageInterface|null $object + * @param array $methodToAttributeMap * @return \DOMElement */ - final protected function createNodeWithTextContent(string $tag, string $textContent): \DOMElement + final protected function createNodeWithTextContent(string $tag, ?string $textContent, ?HasMessageInterface $object = null, array $methodToAttributeMap = []): \DOMElement { $element = $this->createElement($tag); - $element->textContent = $textContent; + + if ($textContent != null) { + $element->textContent = $textContent; + } + + if (isset($object)) { + foreach ($methodToAttributeMap as $attributeName => $method) { + $element->setAttribute($attributeName, $object->$method()); + } + } return $element; } diff --git a/src/HasCodeInterface.php b/src/HasCodeInterface.php new file mode 100644 index 00000000..e98e19b9 --- /dev/null +++ b/src/HasCodeInterface.php @@ -0,0 +1,16 @@ +textContent; } - protected static function getField(\DOMElement $element, string $fieldTagName): ?string + protected static function checkForMessage(HasMessageInterface $object, \DOMElement $element): void + { + if ($element->hasAttribute('msg')) { + $message = new Message(); + $message->setType($element->getAttribute('msgtype')); + $message->setMessage($element->getAttribute('msg')); + $message->setField($element->nodeName); + + $object->addMessage($message); + } + } + + protected static function getAttribute(\DOMElement $element, string $fieldTagName, string $attributeName): ?string + { + $fieldElement = $element->getElementsByTagName($fieldTagName)->item(0); + + if (!isset($fieldElement)) { + return null; + } + + if ($fieldElement->getAttribute($attributeName) === "") { + return null; + } + + return $fieldElement->getAttribute($attributeName); + } + + protected static function getField(\DOMElement $element, string $fieldTagName, $object = null): ?string { $fieldElement = $element->getElementsByTagName($fieldTagName)->item(0); + if (!isset($fieldElement)) { return null; } + if (isset($object)) { + self::checkForMessage($object, $fieldElement); + } + if ($fieldElement->textContent === "") { return null; } return $fieldElement->textContent; } + + protected static function getOfficeCurrencies(AuthenticatedConnection $connection, Office $office): array + { + $currencies = ["base" => '', "reporting" => '']; + + $officeApiConnector = new OfficeApiConnector($connection); + $fullOffice = $officeApiConnector->get($office->getCode()); + + if ($fullOffice->getResult() == 1) { + $currencies['base'] = Util::objectToStr($fullOffice->getBaseCurrency()); + $currencies['reporting'] = Util::objectToStr($fullOffice->getReportingCurrency()); + } + + return $currencies; + } + + protected static function parseDateAttribute(?string $value): ?\DateTimeImmutable + { + if (false !== strtotime($value)) { + return Util::parseDate($value); + } + + return null; + } + + protected static function parseDateTimeAttribute(?string $value): ?\DateTimeImmutable + { + if (false !== strtotime($value)) { + return Util::parseDateTime($value); + } + + return null; + } + + protected static function parseEnumAttribute(string $enumClass, ?string $value) + { + if ($value === null) { + return null; + } + + try { + return new $enumClass($value); + } catch (\Exception $e) { + return null; + } + } + + protected static function parseMoneyAttribute(?float $value, ?string $currency): ?Money + { + if ($value === null || $currency === null) { + return null; + } + + return Util::parseMoney($value, new Currency($currency)); + } + + protected static function parseUnknownEntity(HasMessageInterface $object, \DOMElement $element, string $fieldTagName): string + { + //if (is_a($object, \PhpTwinfield\DimensionGroupDimension::class)) { + // $type = self::getField($element, "type", $object); + //} else { + $type = self::getAttribute($element, $fieldTagName, "dimensiontype"); + //} + + switch ($type) { + //case "ACT": + //return \PhpTwinfield\Activity::class; + //case "AST": + //return \PhpTwinfield\FixedAsset::class; + //case "BAS": + //return \PhpTwinfield\GeneralLedger::class; + case "CRD": + return \PhpTwinfield\Supplier::class; + case "DEB": + return \PhpTwinfield\Customer::class; + //case "KPL": + //return \PhpTwinfield\CostCenter::class; + //case "PNL": + //return \PhpTwinfield\GeneralLedger::class; + //case "PRJ": + //return \PhpTwinfield\Project::class; + default: + throw new \InvalidArgumentException("parseUnknownEntity function was unable to determine class name from \"{$type}\""); + } + } + + /** + * Parse a code referring to a Twinfield Entity / PHP Twinfield object + * + * @param string|null $objectClass + * @param HasMessageInterface $object + * @param \DOMElement $element + * @param string $fieldTagName + * @param array $attributes + * @return HasCodeInterface + */ + protected static function parseObjectAttribute(?string $objectClass, HasMessageInterface $object, \DOMElement $element, string $fieldTagName, array $attributes = []) + { + $value = self::getField($element, $fieldTagName, $object); + + if ($value === null) { + return null; + } + + if ($objectClass === null) { + $objectClass = self::parseUnknownEntity($object, $element, $fieldTagName); + } + + $object2 = new $objectClass(); + $object2->setCode($value); + + foreach ($attributes as $attributeName => $method) { + $object2->$method(self::getAttribute($element, $fieldTagName, $attributeName)); + } + + return $object2; + } } \ No newline at end of file diff --git a/src/Request/Catalog/Catalog.php b/src/Request/Catalog/Catalog.php index cfb21cf8..a56e9b75 100644 --- a/src/Request/Catalog/Catalog.php +++ b/src/Request/Catalog/Catalog.php @@ -5,13 +5,13 @@ * Abstract parent class Catalog. Catalog is the name of the request * for LIST. List is a protected term in PHP so all instances of the word * catalog are just a replacement. - * + * * All aspects of LIST request require a parent element called 'list' - * + * * The constructor makes this element, appends to the itself. All requirements * to add new elements to this dom element are done through * the add() method. - * + * * @package PhpTwinfield * @subpackage Request\Catalog * @author Leon Rowland @@ -23,7 +23,7 @@ abstract class Catalog extends \DOMDocument /** * Holds the element that all * additional elements should be a child of. - * + * * @access private * @var \DOMElement */ @@ -32,7 +32,7 @@ abstract class Catalog extends \DOMDocument /** * Creates the element and adds it to the property * listElement - * + * * @access public */ public function __construct() @@ -45,10 +45,10 @@ public function __construct() /** * Adds additional elements to the dom element. - * + * * See the documentation over what requires to know * what additional elements you need. - * + * * @access protected * @param string $element * @param mixed $value diff --git a/src/Request/Catalog/Office.php b/src/Request/Catalog/Office.php index ac20adec..a055aa20 100644 --- a/src/Request/Catalog/Office.php +++ b/src/Request/Catalog/Office.php @@ -3,7 +3,7 @@ /** * Used to request a list offices - * + * * @package PhpTwinfield * @subpackage Request\Catalog * @author Leon Rowland @@ -14,9 +14,9 @@ class Office extends Catalog { /** * Adds the only required element for this request. - * + * * No other methods exist or are required, - * + * * @access public */ public function __construct() @@ -24,4 +24,4 @@ public function __construct() parent::__construct(); $this->add('type', 'offices'); } -} +} \ No newline at end of file diff --git a/src/Request/Read/Article.php b/src/Request/Read/Article.php index 84561c22..151f4be2 100644 --- a/src/Request/Read/Article.php +++ b/src/Request/Read/Article.php @@ -1,10 +1,11 @@ @@ -14,15 +15,17 @@ class Article extends Read { /** * Sets office and code if they are present. - * + * * @access public + * @param Office|null $office + * @param string $code */ - public function __construct($office = null, $code = null) + public function __construct(?Office $office = null, $code = null) { parent::__construct(); $this->add('type', 'article'); - + if (null !== $office) { $this->setOffice($office); } @@ -31,30 +34,4 @@ public function __construct($office = null, $code = null) $this->setCode($code); } } - - /** - * Sets the office code for this Article request. - * - * @access public - * @param int $office - * @return \PhpTwinfield\Request\Read\Article - */ - public function setOffice($office) - { - $this->add('office', $office); - return $this; - } - - /** - * Sets the code for this Article request. - * - * @access public - * @param string $code - * @return \PhpTwinfield\Request\Read\Article - */ - public function setCode($code) - { - $this->add('code', $code); - return $this; - } } diff --git a/src/Request/Read/BrowseDefinition.php b/src/Request/Read/BrowseDefinition.php index 99e3a7de..47721b22 100644 --- a/src/Request/Read/BrowseDefinition.php +++ b/src/Request/Read/BrowseDefinition.php @@ -12,7 +12,7 @@ class BrowseDefinition extends Read * @param string $code * @param Office|null $office */ - public function __construct(string $code, Office $office = null) + public function __construct(string $code, ?Office $office = null) { parent::__construct(); @@ -26,30 +26,4 @@ public function __construct(string $code, Office $office = null) $this->setCode($code); } } - - /** - * Sets the office code for this BrowseData request. - * - * @access public - * @param Office $office - * @return BrowseDefinition - */ - public function setOffice(Office $office) - { - $this->add('office', $office->getCode()); - return $this; - } - - /** - * Sets the code for this BrowseData request. - * - * @access public - * @param string $code - * @return BrowseDefinition - */ - public function setCode($code) - { - $this->add('code', $code); - return $this; - } } diff --git a/src/Request/Read/Customer.php b/src/Request/Read/Customer.php index a7d827b2..a8d9f3fa 100644 --- a/src/Request/Read/Customer.php +++ b/src/Request/Read/Customer.php @@ -1,10 +1,12 @@ @@ -16,62 +18,24 @@ class Customer extends Read /** * Sets the to dimensions for the request and * sets the dimtype, office and code if they are present. - * + * * @access public + * @param Office|null $office + * @param string $code */ - public function __construct($office = null, $code = null, $dimType = 'DEB') + public function __construct(?Office $office = null, $code = null) { parent::__construct(); $this->add('type', 'dimensions'); - + $this->add('dimtype', 'DEB'); + if (null !== $office) { $this->setOffice($office); } - + if (null !== $code) { $this->setCode($code); } - - $this->setDimType($dimType); - } - - /** - * Sets the office code for this customer request. - * - * @access public - * @param int $office - * @return \PhpTwinfield\Request\Read\Customer - */ - public function setOffice($office) - { - $this->add('office', $office); - return $this; - } - - /** - * Sets the code for this customer request. - * - * @access public - * @param string $code - * @return \PhpTwinfield\Request\Read\Customer - */ - public function setCode($code) - { - $this->add('code', $code); - return $this; - } - - /** - * Sets the dimtype for the request. - * - * @access public - * @param string $dimType - * @return \PhpTwinfield\Request\Read\Customer - */ - public function setDimType($dimType) - { - $this->add('dimtype', $dimType); - return $this; } } diff --git a/src/Request/Read/Invoice.php b/src/Request/Read/Invoice.php index 27aec93a..07402a0a 100644 --- a/src/Request/Read/Invoice.php +++ b/src/Request/Read/Invoice.php @@ -1,84 +1,59 @@ - * @copyright (c) 2013, Pronamic + * @copyright (c) 2013, Pronamic * @version 0.0.1 */ class Invoice extends Read { /** * Sets the to salesinvoice for the request - * and sets the office, code and number if they + * and sets the office, code and invoice number if they * are present. - * + * * @access public - * @param int $office + * @param Office|null $office * @param string $code - * @param int $number + * @param int $invoiceNumber */ - public function __construct($office = null, $code = null, $number = null) + public function __construct(?Office $office = null, $code = null, $invoiceNumber = null) { parent::__construct(); $this->add('type', 'salesinvoice'); - + if (null !== $office) { $this->setOffice($office); } - + if (null !== $code) { $this->setCode($code); } - - if (null !== $number) { - $this->setNumber($number); - } - } - /** - * Sets the office code for this salesinvoice - * request. It is an optional field. - * - * @access public - * @param int $office - * @return \PhpTwinfield\Request\Read\Invoice - */ - public function setOffice($office) - { - $this->add('office', $office); - return $this; + if (null !== $invoiceNumber) { + $this->setInvoiceNumber($invoiceNumber); + } } - /** - * Sets the code for this salesinvoice request. + /** + * Sets the invoice number for this request. * * @access public - * @param string $code - * @return \PhpTwinfield\Request\Read\Invoice - */ - public function setCode($code) - { - $this->add('code', $code); - return $this; - } - - /** - * Sets the invoicenumber for this request. - * - * @access public - * @param int $number + * @param string $invoiceNumber * @return \PhpTwinfield\Request\Read\Invoice */ - public function setNumber($number) + public function setInvoiceNumber($invoiceNumber) { - $this->add('invoicenumber', $number); + $this->add('invoicenumber', $invoiceNumber); return $this; } } diff --git a/src/Request/Read/Read.php b/src/Request/Read/Read.php index 31b8899c..c3648968 100644 --- a/src/Request/Read/Read.php +++ b/src/Request/Read/Read.php @@ -1,16 +1,18 @@ dom element are done through the add() * method. - * + * * @package PhpTwinfield * @subpackage Request\Read * @author Leon Rowland @@ -21,8 +23,8 @@ abstract class Read extends \DOMDocument { /** * Holds the element that all - * additional elements shoudl be a child of. - * + * additional elements should be a child of. + * * @access private * @var \DOMElement */ @@ -31,7 +33,7 @@ abstract class Read extends \DOMDocument /** * Creates the element and adds it to the property * readElement - * + * * @access public */ public function __construct() @@ -44,10 +46,10 @@ public function __construct() /** * Adds additional elements to the dom element. - * + * * See the documentation over what requires to know * and what additional elements you need. - * + * * @access protected * @param string $element * @param mixed $value @@ -58,4 +60,56 @@ protected function add($element, $value) $_element = $this->createElement($element, $value); $this->readElement->appendChild($_element); } + + /** + * Sets the office code for this request. + * + * @access public + * @param Office $office + * @return \PhpTwinfield\Request\Read\Read + */ + public function setOffice(Office $office) + { + $this->add('office', $office); + return $this; + } + + /** + * Sets the code for this request. + * + * @access public + * @param string $code + * @return \PhpTwinfield\Request\Read\Read + */ + public function setCode($code) + { + $this->add('code', $code); + return $this; + } + + /** + * Sets the dimtype for this request. + * + * @access public + * @param string $dimType + * @return \PhpTwinfield\Request\Read\Read + */ + public function setDimType($dimType) + { + $this->add('dimtype', $dimType); + return $this; + } + + /** + * Sets the number for this request. + * + * @access public + * @param string $number + * @return \PhpTwinfield\Request\Read\Read + */ + public function setNumber($number) + { + $this->add('number', $number); + return $this; + } } diff --git a/src/Request/Read/Supplier.php b/src/Request/Read/Supplier.php index 2abfc86a..a6ba3d96 100644 --- a/src/Request/Read/Supplier.php +++ b/src/Request/Read/Supplier.php @@ -1,10 +1,12 @@ @@ -15,63 +17,25 @@ class Supplier extends Read { /** * Sets the to dimensions for the request and - * sets the dimtype, office and code if they are present. - * + * sets the office and code if they are present. + * * @access public + * @param Office $office + * @param string $code */ - public function __construct($office = null, $code = null, $dimType = 'CRD') + public function __construct(?Office $office = null, $code = null) { parent::__construct(); $this->add('type', 'dimensions'); - + $this->add('dimtype', 'CRD'); + if (null !== $office) { $this->setOffice($office); } - + if (null !== $code) { $this->setCode($code); } - - $this->setDimType($dimType); - } - - /** - * Sets the office code for this customer request. - * - * @access public - * @param int $office - * @return $this - */ - public function setOffice($office) - { - $this->add('office', $office); - return $this; - } - - /** - * Sets the code for this customer request. - * - * @access public - * @param string $code - * @return $this - */ - public function setCode($code) - { - $this->add('code', $code); - return $this; - } - - /** - * Sets the dimtype for the request. - * - * @access public - * @param string $dimType - * @return $this - */ - public function setDimType($dimType) - { - $this->add('dimtype', $dimType); - return $this; } } diff --git a/src/Request/Read/Transaction.php b/src/Request/Read/Transaction.php index 00bdbad7..5c224d05 100644 --- a/src/Request/Read/Transaction.php +++ b/src/Request/Read/Transaction.php @@ -6,7 +6,7 @@ /** * Used to request a specific transaction from a certain * office, code and number. - * + * * @package PhpTwinfield * @subpackage Request\Read * @author Leon Rowland @@ -18,67 +18,28 @@ class Transaction extends Read /** * Sets the to transaction for the request and * sets the office, code and number if they are present. - * + * * @access public - * @param int $office + * @param Office $office * @param string $code * @param int $number */ - public function __construct($office = null, $code = null, $number = null) + public function __construct(?Office $office = null, $code = null, $number = null) { parent::__construct(); - + $this->add('type', 'transaction'); - + if (null !== $office) { $this->setOffice($office); } - + if (null !== $code) { $this->setCode($code); } - + if (null !== $number) { $this->setNumber($number); } } - - /** - * Sets the office code for this transaction request. - * - * @access public - * @param Office $office - * @return \PhpTwinfield\Request\Read\Transaction - */ - public function setOffice(Office $office) - { - $this->add('office', $office->getCode()); - return $this; - } - - /** - * Sets the code for this transaction request. - * - * @access public - * @param string $code - * @return \PhpTwinfield\Request\Read\Transaction - */ - public function setCode($code) - { - $this->add('code', $code); - return $this; - } - - /** - * Sets the number for this transaction request - * - * @access public - * @param int $number - * @return \PhpTwinfield\Request\Read\Transaction - */ - public function setNumber($number) - { - $this->add('number', $number); - return $this; - } } diff --git a/src/Response/MappedResponseCollection.php b/src/Response/MappedResponseCollection.php index 0c953615..779e17e7 100644 --- a/src/Response/MappedResponseCollection.php +++ b/src/Response/MappedResponseCollection.php @@ -95,4 +95,4 @@ private function countResponses(bool $successful): int return $count; } -} +} \ No newline at end of file diff --git a/src/Response/Response.php b/src/Response/Response.php index 43ea9c6e..9e842a82 100644 --- a/src/Response/Response.php +++ b/src/Response/Response.php @@ -45,7 +45,7 @@ public static function fromString(string $xml) return new self($document); } - + public function __construct(\DOMDocument $responseDocument) { $this->responseDocument = $responseDocument; @@ -145,4 +145,4 @@ public function getWarningMessages(): array { return $this->getMessages('warning'); } -} +} \ No newline at end of file diff --git a/src/Secure/OpenIdConnectAuthentication.php b/src/Secure/OpenIdConnectAuthentication.php index 36ee7a3f..61c5b1db 100644 --- a/src/Secure/OpenIdConnectAuthentication.php +++ b/src/Secure/OpenIdConnectAuthentication.php @@ -48,11 +48,13 @@ class OpenIdConnectAuthentication extends AuthenticatedConnection * Please note that for most calls an office is mandatory. If you do not supply it * you have to pass it with every request, or call setOffice. */ - public function __construct(OAuthProvider $provider, string $refreshToken, ?Office $office) + public function __construct(OAuthProvider $provider, string $refreshToken, ?Office $office, string $accessToken = null, string $cluster = null) { $this->provider = $provider; + $this->accessToken = $accessToken; $this->refreshToken = $refreshToken; $this->office = $office; + $this->cluster = $cluster; } public function setOffice(?Office $office) @@ -95,8 +97,10 @@ protected function login(): void $this->refreshToken(); } - $validationResult = $this->validateToken(); - $this->cluster = $validationResult["twf.clusterUrl"]; + if ($this->cluster === null) { + $validationResult = $this->validateToken(); + $this->cluster = $validationResult["twf.clusterUrl"]; + } } /** diff --git a/src/Services/BaseService.php b/src/Services/BaseService.php index 8c424909..9391637d 100644 --- a/src/Services/BaseService.php +++ b/src/Services/BaseService.php @@ -41,4 +41,9 @@ public function __construct(string $wsdl = null, array $options = []) parent::__construct($wsdl, $options); } + + public function __call($func, $args) + { + return $this->__soapCall($func, $args); + } } diff --git a/src/Services/ProcessXmlService.php b/src/Services/ProcessXmlService.php index f6204e5f..2c230c94 100644 --- a/src/Services/ProcessXmlService.php +++ b/src/Services/ProcessXmlService.php @@ -37,7 +37,7 @@ public function chunk(array $items): array * * If there is an error in the response, an Exception is thrown, but it can also throw SoapFaults. * - * Note that you will probably have to chunk the objects into several documents if you want to send many objects. + * Note that you will probably have to chunk the objects into several documents if you want to send many objects. * * @param \DOMDocument $document * @return Response The response from the request diff --git a/src/Util.php b/src/Util.php index de8e09c5..cb64e2b3 100644 --- a/src/Util.php +++ b/src/Util.php @@ -11,15 +11,36 @@ final class Util { - public static function formatMoney(Money $money): string + /** + * Format a money object to string according to Twinfield specifications. + * + * @param Money|null $money + * @return string|null + */ + public static function formatMoney(?Money $money): ?string { + if ($money === null) { + return null; + } + $decimalformatter = new DecimalMoneyFormatter(new ISOCurrencies()); return $decimalformatter->format($money); } - public static function parseMoney(string $moneyString, Currency $currency): Money + /** + * Parse a money string and Currency object. + * + * @param string|null $moneyString + * @param Currency|null $currency + * @return Money|null + */ + public static function parseMoney(?string $moneyString, ?Currency $currency): ?Money { + if ($moneyString === null || $currency === null) { + return null; + } + $parser = new DecimalMoneyParser(new ISOCurrencies()); return $parser->parse($moneyString, $currency); } @@ -27,23 +48,31 @@ public static function parseMoney(string $moneyString, Currency $currency): Mone /** * Format a date according to Twinfield specifications. * - * @param \DateTimeInterface $date - * @return string + * @param \DateTimeInterface|null $date + * @return string|null */ - public static function formatDate(\DateTimeInterface $date): string + public static function formatDate(?\DateTimeInterface $date): ?string { + if ($date === null) { + return null; + } + return $date->format("Ymd"); } /** * Parse a date string from a Twinfield XML. * - * @param string $dateString - * @return \DateTimeImmutable + * @param string|null $dateString + * @return \DateTimeImmutable|null * @throws Exception */ - public static function parseDate(string $dateString): \DateTimeImmutable + public static function parseDate(?string $dateString): ?\DateTimeImmutable { + if ($dateString === null) { + return null; + } + $date = \DateTimeImmutable::createFromFormat("Ymd|", $dateString); if (false === $date) { @@ -53,15 +82,34 @@ public static function parseDate(string $dateString): \DateTimeImmutable return $date; } + /** + * Format a date time according to Twinfield specifications. + * + * @param \DateTimeInterface|null $datetime + * @return string|null + */ + public static function formatDateTime(?\DateTimeInterface $datetime): ?string + { + if ($datetime === null) { + return null; + } + + return $datetime->format("YmdHis"); + } + /** * Parse a date time string from a Twinfield XML. * - * @param string $dateString - * @return \DateTimeImmutable + * @param string|null $dateString + * @return \DateTimeImmutable|null * @throws Exception */ - public static function parseDateTime(string $dateString) + public static function parseDateTime(?string $dateString): ?\DateTimeImmutable { + if ($dateString === null) { + return null; + } + $date = \DateTimeImmutable::createFromFormat("YmdHis", $dateString); if (false === $date) { @@ -72,29 +120,42 @@ public static function parseDateTime(string $dateString) } /** - * @param bool $boolean - * @return string + * @param bool|null $boolean + * @return string|null */ - public static function formatBoolean(bool $boolean): string + public static function formatBoolean(?bool $boolean): ?string { + if ($boolean === null) { + return null; + } + return $boolean ? "true" : "false"; } /** - * @param string $input - * @return bool - * @throws Exception + * @param string|null $value + * @return bool|null */ - public static function parseBoolean(string $input): bool + public static function parseBoolean(?string $value): ?bool { - switch ($input) { - case "true": - return true; - case "false": - return false; + if ($value === null) { + return null; } + + return filter_var($value, FILTER_VALIDATE_BOOLEAN); + } - throw new Exception("Unknown boolean value \"{$input}\"."); + /** + * @param HasCodeInterface|null $object + * @return string|null + */ + public static function objectToStr(?HasCodeInterface $object): ?string + { + if ($object === null) { + return null; + } + + return $object->getCode(); } /**