123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662 |
- <?php
- namespace Braintree;
- use InvalidArgumentException;
- /**
- * Braintree CustomerGateway module
- * Creates and manages Customers
- *
- * <b>== More information ==</b>
- *
- * For more detailed information on Customers, see {@link https://developers.braintreepayments.com/reference/response/customer/php https://developers.braintreepayments.com/reference/response/customer/php}
- *
- * @package Braintree
- * @category Resources
- */
- class CustomerGateway
- {
- private $_gateway;
- private $_config;
- private $_http;
- public function __construct($gateway)
- {
- $this->_gateway = $gateway;
- $this->_config = $gateway->config;
- $this->_config->assertHasAccessTokenOrKeys();
- $this->_http = new Http($gateway->config);
- }
- public function all()
- {
- $path = $this->_config->merchantPath() . '/customers/advanced_search_ids';
- $response = $this->_http->post($path);
- $pager = [
- 'object' => $this,
- 'method' => 'fetch',
- 'methodArgs' => [[]]
- ];
- return new ResourceCollection($response, $pager);
- }
- public function fetch($query, $ids)
- {
- $criteria = [];
- foreach ($query as $term) {
- $criteria[$term->name] = $term->toparam();
- }
- $criteria["ids"] = CustomerSearch::ids()->in($ids)->toparam();
- $path = $this->_config->merchantPath() . '/customers/advanced_search';
- $response = $this->_http->post($path, ['search' => $criteria]);
- return Util::extractattributeasarray(
- $response['customers'],
- 'customer'
- );
- }
- /**
- * Creates a customer using the given +attributes+. If <tt>:id</tt> is not passed,
- * the gateway will generate it.
- *
- * <code>
- * $result = Customer::create(array(
- * 'first_name' => 'John',
- * 'last_name' => 'Smith',
- * 'company' => 'Smith Co.',
- * 'email' => 'john@smith.com',
- * 'website' => 'www.smithco.com',
- * 'fax' => '419-555-1234',
- * 'phone' => '614-555-1234'
- * ));
- * if($result->success) {
- * echo 'Created customer ' . $result->customer->id;
- * } else {
- * echo 'Could not create customer, see result->errors';
- * }
- * </code>
- *
- * @access public
- * @param array $attribs
- * @return Braintree_Result_Successful|Braintree_Result_Error
- */
- public function create($attribs = [])
- {
- Util::verifyKeys(self::createSignature(), $attribs);
- return $this->_doCreate('/customers', ['customer' => $attribs]);
- }
- /**
- * attempts the create operation assuming all data will validate
- * returns a Customer object instead of a Result
- *
- * @access public
- * @param array $attribs
- * @return Customer
- * @throws Exception\ValidationError
- */
- public function createNoValidate($attribs = [])
- {
- $result = $this->create($attribs);
- return Util::returnObjectOrThrowException(__CLASS__, $result);
- }
- /**
- * create a customer from a TransparentRedirect operation
- *
- * @deprecated since version 2.3.0
- * @access public
- * @param array $attribs
- * @return Customer
- */
- public function createFromTransparentRedirect($queryString)
- {
- trigger_error("DEPRECATED: Please use TransparentRedirectRequest::confirm", E_USER_NOTICE);
- $params = TransparentRedirect::parseAndValidateQueryString(
- $queryString
- );
- return $this->_doCreate(
- '/customers/all/confirm_transparent_redirect_request',
- ['id' => $params['id']]
- );
- }
- /**
- *
- * @deprecated since version 2.3.0
- * @access public
- * @param none
- * @return string
- */
- public function createCustomerUrl()
- {
- trigger_error("DEPRECATED: Please use TransparentRedirectRequest::url", E_USER_NOTICE);
- return $this->_config->baseUrl() . $this->_config->merchantPath() .
- '/customers/all/create_via_transparent_redirect_request';
- }
- /**
- * creates a full array signature of a valid create request
- * @return array gateway create request format
- */
- public static function createSignature()
- {
- $creditCardSignature = CreditCardGateway::createSignature();
- unset($creditCardSignature[array_search('customerId', $creditCardSignature)]);
- $signature = [
- 'id', 'company', 'email', 'fax', 'firstName',
- 'lastName', 'phone', 'website', 'deviceData',
- 'deviceSessionId', 'fraudMerchantId', 'paymentMethodNonce',
- ['riskData' =>
- ['customerBrowser', 'customerIp', 'customer_browser', 'customer_ip']
- ],
- ['creditCard' => $creditCardSignature],
- ['customFields' => ['_anyKey_']],
- ['options' => [
- ['paypal' => [
- 'payee_email',
- 'payeeEmail',
- 'order_id',
- 'orderId',
- 'custom_field',
- 'customField',
- 'description',
- 'amount',
- ['shipping' =>
- [
- 'firstName', 'lastName', 'company', 'countryName',
- 'countryCodeAlpha2', 'countryCodeAlpha3', 'countryCodeNumeric',
- 'extendedAddress', 'locality', 'postalCode', 'region',
- 'streetAddress'],
- ],
- ]]
- ]],
- ];
- return $signature;
- }
- /**
- * creates a full array signature of a valid update request
- * @return array update request format
- */
- public static function updateSignature()
- {
- $creditCardSignature = CreditCardGateway::updateSignature();
- foreach($creditCardSignature AS $key => $value) {
- if(is_array($value) and array_key_exists('options', $value)) {
- array_push($creditCardSignature[$key]['options'], 'updateExistingToken');
- }
- }
- $signature = [
- 'id', 'company', 'email', 'fax', 'firstName',
- 'lastName', 'phone', 'website', 'deviceData',
- 'deviceSessionId', 'fraudMerchantId', 'paymentMethodNonce', 'defaultPaymentMethodToken',
- ['creditCard' => $creditCardSignature],
- ['customFields' => ['_anyKey_']],
- ['options' => [
- ['paypal' => [
- 'payee_email',
- 'payeeEmail',
- ['shipping' =>
- [
- 'firstName', 'lastName', 'company', 'countryName',
- 'countryCodeAlpha2', 'countryCodeAlpha3', 'countryCodeNumeric',
- 'extendedAddress', 'locality', 'postalCode', 'region',
- 'streetAddress'],
- ],
- ]],
- ]],
- ];
- return $signature;
- }
- /**
- * find a customer by id
- *
- * @access public
- * @param string id customer Id
- * @param string associationFilterId association filter Id
- * @return Customer|boolean The customer object or false if the request fails.
- * @throws Exception\NotFound
- */
- public function find($id, $associationFilterId = null)
- {
- $this->_validateId($id);
- try {
- $queryParams = '';
- if ($associationFilterId) {
- $queryParams = '?association_filter_id=' . $associationFilterId;
- }
- $path = $this->_config->merchantPath() . '/customers/' . $id . $queryParams;
- $response = $this->_http->get($path);
- return Customer::factory($response['customer']);
- } catch (Exception\NotFound $e) {
- throw new Exception\NotFound(
- 'customer with id ' . $id . ' not found'
- );
- }
- }
- /**
- * credit a customer for the passed transaction
- *
- * @access public
- * @param int $customerId
- * @param array $transactionAttribs
- * @return Result\Successful|Result\Error
- */
- public function credit($customerId, $transactionAttribs)
- {
- $this->_validateId($customerId);
- return Transaction::credit(
- array_merge($transactionAttribs,
- ['customerId' => $customerId]
- )
- );
- }
- /**
- * credit a customer, assuming validations will pass
- *
- * returns a Transaction object on success
- *
- * @access public
- * @param int $customerId
- * @param array $transactionAttribs
- * @return Transaction
- * @throws Exception\ValidationError
- */
- public function creditNoValidate($customerId, $transactionAttribs)
- {
- $result = $this->credit($customerId, $transactionAttribs);
- return Util::returnObjectOrThrowException('Braintree\Transaction', $result);
- }
- /**
- * delete a customer by id
- *
- * @param string $customerId
- */
- public function delete($customerId)
- {
- $this->_validateId($customerId);
- $path = $this->_config->merchantPath() . '/customers/' . $customerId;
- $this->_http->delete($path);
- return new Result\Successful();
- }
- /**
- * create a new sale for a customer
- *
- * @param string $customerId
- * @param array $transactionAttribs
- * @return Result\Successful|Result\Error
- * @see Transaction::sale()
- */
- public function sale($customerId, $transactionAttribs)
- {
- $this->_validateId($customerId);
- return Transaction::sale(
- array_merge($transactionAttribs,
- ['customerId' => $customerId]
- )
- );
- }
- /**
- * create a new sale for a customer, assuming validations will pass
- *
- * returns a Transaction object on success
- * @access public
- * @param string $customerId
- * @param array $transactionAttribs
- * @return Transaction
- * @throws Exception\ValidationsFailed
- * @see Transaction::sale()
- */
- public function saleNoValidate($customerId, $transactionAttribs)
- {
- $result = $this->sale($customerId, $transactionAttribs);
- return Util::returnObjectOrThrowException('Braintree\Transaction', $result);
- }
- /**
- * Returns a ResourceCollection of customers matching the search query.
- *
- * If <b>query</b> is a string, the search will be a basic search.
- * If <b>query</b> is a hash, the search will be an advanced search.
- * For more detailed information and examples, see {@link https://developers.braintreepayments.com/reference/request/customer/search/php https://developers.braintreepayments.com/reference/request/customer/search/php}
- *
- * @param mixed $query search query
- * @return ResourceCollection
- * @throws InvalidArgumentException
- */
- public function search($query)
- {
- $criteria = [];
- foreach ($query as $term) {
- $result = $term->toparam();
- if(is_null($result) || empty($result)) {
- throw new InvalidArgumentException('Operator must be provided');
- }
- $criteria[$term->name] = $term->toparam();
- }
- $path = $this->_config->merchantPath() . '/customers/advanced_search_ids';
- $response = $this->_http->post($path, ['search' => $criteria]);
- $pager = [
- 'object' => $this,
- 'method' => 'fetch',
- 'methodArgs' => [$query]
- ];
- return new ResourceCollection($response, $pager);
- }
- /**
- * updates the customer record
- *
- * if calling this method in static context, customerId
- * is the 2nd attribute. customerId is not sent in object context.
- *
- * @access public
- * @param string $customerId (optional)
- * @param array $attributes
- * @return Result\Successful|Result\Error
- */
- public function update($customerId, $attributes)
- {
- Util::verifyKeys(self::updateSignature(), $attributes);
- $this->_validateId($customerId);
- return $this->_doUpdate(
- 'put',
- '/customers/' . $customerId,
- ['customer' => $attributes]
- );
- }
- /**
- * update a customer record, assuming validations will pass
- *
- * if calling this method in static context, customerId
- * is the 2nd attribute. customerId is not sent in object context.
- * returns a Customer object on success
- *
- * @access public
- * @param string $customerId
- * @param array $attributes
- * @return Customer
- * @throws Exception\ValidationsFailed
- */
- public function updateNoValidate($customerId, $attributes)
- {
- $result = $this->update($customerId, $attributes);
- return Util::returnObjectOrThrowException(__CLASS__, $result);
- }
- /**
- *
- * @deprecated since version 2.3.0
- * @access public
- * @return string
- */
- public function updateCustomerUrl()
- {
- trigger_error("DEPRECATED: Please use TransparentRedirectRequest::url", E_USER_NOTICE);
- return $this->_config->baseUrl() . $this->_config->merchantPath() .
- '/customers/all/update_via_transparent_redirect_request';
- }
- /**
- * update a customer from a TransparentRedirect operation
- *
- * @deprecated since version 2.3.0
- * @access public
- * @param string $queryString
- * @return object
- */
- public function updateFromTransparentRedirect($queryString)
- {
- trigger_error("DEPRECATED: Please use TransparentRedirectRequest::confirm", E_USER_NOTICE);
- $params = TransparentRedirect::parseAndValidateQueryString(
- $queryString
- );
- return $this->_doUpdate(
- 'post',
- '/customers/all/confirm_transparent_redirect_request',
- ['id' => $params['id']]
- );
- }
- /* instance methods */
- /**
- * sets instance properties from an array of values
- *
- * @ignore
- * @access protected
- * @param array $customerAttribs array of customer data
- * @return void
- */
- protected function _initialize($customerAttribs)
- {
- // set the attributes
- $this->_attributes = $customerAttribs;
- // map each address into its own object
- $addressArray = [];
- if (isset($customerAttribs['addresses'])) {
- foreach ($customerAttribs['addresses'] AS $address) {
- $addressArray[] = Address::factory($address);
- }
- }
- $this->_set('addresses', $addressArray);
- // map each creditCard into its own object
- $creditCardArray = [];
- if (isset($customerAttribs['creditCards'])) {
- foreach ($customerAttribs['creditCards'] AS $creditCard) {
- $creditCardArray[] = CreditCard::factory($creditCard);
- }
- }
- $this->_set('creditCards', $creditCardArray);
- // map each coinbaseAccount into its own object
- $coinbaseAccountArray = [];
- if (isset($customerAttribs['coinbaseAccounts'])) {
- foreach ($customerAttribs['coinbaseAccounts'] AS $coinbaseAccount) {
- $coinbaseAccountArray[] = CoinbaseAccount::factory($coinbaseAccount);
- }
- }
- $this->_set('coinbaseAccounts', $coinbaseAccountArray);
- // map each paypalAccount into its own object
- $paypalAccountArray = [];
- if (isset($customerAttribs['paypalAccounts'])) {
- foreach ($customerAttribs['paypalAccounts'] AS $paypalAccount) {
- $paypalAccountArray[] = PayPalAccount::factory($paypalAccount);
- }
- }
- $this->_set('paypalAccounts', $paypalAccountArray);
- // map each applePayCard into its own object
- $applePayCardArray = [];
- if (isset($customerAttribs['applePayCards'])) {
- foreach ($customerAttribs['applePayCards'] AS $applePayCard) {
- $applePayCardArray[] = ApplePayCard::factory($applePayCard);
- }
- }
- $this->_set('applePayCards', $applePayCardArray);
- // map each androidPayCard into its own object
- $androidPayCardArray = [];
- if (isset($customerAttribs['androidPayCards'])) {
- foreach ($customerAttribs['androidPayCards'] AS $androidPayCard) {
- $androidPayCardArray[] = AndroidPayCard::factory($androidPayCard);
- }
- }
- $this->_set('androidPayCards', $androidPayCardArray);
- $this->_set('paymentMethods', array_merge($this->creditCards, $this->paypalAccounts, $this->applePayCards, $this->coinbaseAccounts, $this->androidPayCards));
- }
- /**
- * returns a string representation of the customer
- * @return string
- */
- public function __toString()
- {
- return __CLASS__ . '[' .
- Util::attributesToString($this->_attributes) .']';
- }
- /**
- * returns false if comparing object is not a Customer,
- * or is a Customer with a different id
- *
- * @param object $otherCust customer to compare against
- * @return boolean
- */
- public function isEqual($otherCust)
- {
- return !($otherCust instanceof Customer) ? false : $this->id === $otherCust->id;
- }
- /**
- * returns an array containt all of the customer's payment methods
- *
- * @return array
- */
- public function paymentMethods()
- {
- return $this->paymentMethods;
- }
- /**
- * returns the customer's default payment method
- *
- * @return CreditCard|PayPalAccount|ApplePayCard|AndroidPayCard
- */
- public function defaultPaymentMethod()
- {
- $defaultPaymentMethods = array_filter($this->paymentMethods, 'Braintree\\Customer::_defaultPaymentMethodFilter');
- return current($defaultPaymentMethods);
- }
- public static function _defaultPaymentMethodFilter($paymentMethod)
- {
- return $paymentMethod->isDefault();
- }
- /* private class properties */
- /**
- * @access protected
- * @var array registry of customer data
- */
- protected $_attributes = [
- 'addresses' => '',
- 'company' => '',
- 'creditCards' => '',
- 'email' => '',
- 'fax' => '',
- 'firstName' => '',
- 'id' => '',
- 'lastName' => '',
- 'phone' => '',
- 'createdAt' => '',
- 'updatedAt' => '',
- 'website' => '',
- ];
- /**
- * sends the create request to the gateway
- *
- * @ignore
- * @param string $subPath
- * @param array $params
- * @return mixed
- */
- public function _doCreate($subPath, $params)
- {
- $fullPath = $this->_config->merchantPath() . $subPath;
- $response = $this->_http->post($fullPath, $params);
- return $this->_verifyGatewayResponse($response);
- }
- /**
- * verifies that a valid customer id is being used
- * @ignore
- * @param string customer id
- * @throws InvalidArgumentException
- */
- private function _validateId($id = null) {
- if (is_null($id)) {
- throw new InvalidArgumentException(
- 'expected customer id to be set'
- );
- }
- if (!preg_match('/^[0-9A-Za-z_-]+$/', $id)) {
- throw new InvalidArgumentException(
- $id . ' is an invalid customer id.'
- );
- }
- }
- /* private class methods */
- /**
- * sends the update request to the gateway
- *
- * @ignore
- * @param string $subPath
- * @param array $params
- * @return mixed
- */
- private function _doUpdate($httpVerb, $subPath, $params)
- {
- $fullPath = $this->_config->merchantPath() . $subPath;
- $response = $this->_http->$httpVerb($fullPath, $params);
- return $this->_verifyGatewayResponse($response);
- }
- /**
- * generic method for validating incoming gateway responses
- *
- * creates a new Customer object and encapsulates
- * it inside a Result\Successful object, or
- * encapsulates a Errors object inside a Result\Error
- * alternatively, throws an Unexpected exception if the response is invalid.
- *
- * @ignore
- * @param array $response gateway response values
- * @return Result\Successful|Result\Error
- * @throws Exception\Unexpected
- */
- private function _verifyGatewayResponse($response)
- {
- if (isset($response['customer'])) {
- // return a populated instance of Customer
- return new Result\Successful(
- Customer::factory($response['customer'])
- );
- } else if (isset($response['apiErrorResponse'])) {
- return new Result\Error($response['apiErrorResponse']);
- } else {
- throw new Exception\Unexpected(
- "Expected customer or apiErrorResponse"
- );
- }
- }
- }
- class_alias('Braintree\CustomerGateway', 'Braintree_CustomerGateway');
|