*/ class Customer extends CrmClientModel { /** * The user hashcode, this is link with the customer and the brand it is related to * It is used to identify the customer itself. * * Validate: UUID, in customer_infos * * Required * Min length 36 * Max length 36 * Field Type varchar * * @var string */ private $hashcode; /** * An RFC Valid Email * * Validate: rfc,dns,spoof,filter * * Required * Min length N/A * Max length 255 * Field Type varchar * * @var string */ private $email = null; /** * The user password * This is set only when creating a user * Otherwise it has to be set to null * * Validate: case_diff,numbers,letters,symbols,min:8 * * Min length 8 * Max length 255 * Field Type varchar * * @var string */ private $password = null; /** * First name * * Required * Min length 2 * Max length 255 * Field Type varchar * * @var string */ private $firstname = null; /** * Last name * * Required * Min length 2 * Max length 255 * Field Type varchar * * @var string */ private $lastname = null; /** * Birth date * * Validate: date_format:Y-m-d * * Required * Field Type Date * @var string */ private $birth_date = null; /** * The user phone * * Validate: sometimes,string * * Required * Min length NA * Max length 255 * Field Type varchar * * @var string */ private $phone = null; /** * The user address (street number, name, etc) * * Validate: sometimes,string * * Min length NA * Max length 255 * Field Type varchar * * @var string */ private $address = null; /** * The user address 2nd part (street number, name, more, etc) * * Validate: sometimes,string * * Min length NA * Max length 255 * Field Type varchar * * @var string */ private $address2 = null; /** * The user address city * * Validate: sometimes,string * * Min length NA * Max length 255 * Field Type varchar * * @var string */ private $city = null; /** * The user address postcode * * Validate: string * * Required * Min length NA * Max length 255 * Field Type varchar * * @var string */ private $postcode = null; /** * The user address postcode * * Validate: sometimes, in Country::toValues() * * Required * Field Type tinyInt * * @var \LDC\LDCCRM\Enums\Country */ private $country = null; /** * The user optin choice * * Validate: boolean * * Required * Field Type TinyInt * * @var boolean */ private $opt_in = false; /** * Is the account activated ? * * This field is read only * * @var boolean */ private $status = false; /** * The last time the account was connected * * This field is read only * * @var string */ private $last_connection = null; /** * The crm customer fields * * @var array */ protected $modelFields = [ 'hashcode', 'email', 'firstname', 'password', 'lastname', 'birth_date', 'phone', 'address', 'address2', 'city', 'postcode', 'country', 'opt_in', 'status', 'last_connection' ]; /** * The crm customer fields * the should not be visible * * @var array */ protected $invisibleFields = [ 'password' ]; /** * Validation rules * * @var array */ protected static $validation = [ 'hashcode' => 'required|uuid', 'email' => 'required|email', 'firstname' => 'required|string|min:1|max:255', 'lastname' => 'required|string|min:1|max:255', 'password' => 'required|min:8|max:255|mixedCase|containDigit|containSymbol', 'birth_date' => 'required|date_format:Y-m-d', 'phone' => 'sometimes|nullable|string|max:255', 'address' => 'sometimes|string|max:255', 'address2' => 'sometimes|string|max:255', 'city' => 'sometimes|string|min:2|max:255', 'postcode' => 'sometimes|string|max:255', 'country' => ['sometimes'], 'opt_in' => 'required|bool', 'status' => 'required|bool', 'last_connection' => 'sometimes|date' ]; /** * Customer * * @param array $properties * @throws \LDC\LDCCRM\Exceptions\ValidationException If a field could not be validated. */ public function __construct(array $properties = []) { parent::__construct(); $this->fill($properties); return $this; } /** * Generic accessor * * @param string $field * @return mixed|null Returns null if the property was not found any way. */ public function __get(string $field) { $props = \array_diff( $this->modelFields, $this->invisibleFields ); if (in_array($field, $props)) { if ($field === 'country' and !\is_object($this->{$field})) { return Country::make($this->{$field}); } } return parent::__get($field); } /** * Set prop on the model. * * @param string $field * @param mixed $value * @return void * @throws \LDC\LDCCRM\Exceptions\ValidationException If a field could not be validated. * @throws \LDC\LDCCRM\Exceptions\AccessError If trying to set a value on a unknown property. */ public function __set(string $field, $value): void { if ($field === 'country') { $value = (\is_object($value) and get_class($value) === Country::class) ? $value->value : $value; } parent::__set($field, $value); } /** * Fill values into model using validation rules. * * @param array $properties * @return void * @throws \LDC\LDCCRM\Exceptions\ValidationException If a field could not be validated. */ public function fill(array $properties) { if (isset($properties['country'])) { try { $properties['country'] = (\is_object($properties['country']) and get_class($properties['country']) === Country::class) ? $properties['country']->value : (ctype_digit($properties['country']) ? (int)$properties['country'] : $properties['country']); } catch (TypeError | \BadMethodCallException $e) { // * Cast anyway $properties['country'] = (int)$properties['country']; } } parent::fill($properties); } /** * Validate all model properties * * @param array $ignore * @return array the validated values * @throws \LDC\LDCCRM\Exceptions\ValidationException If a field could not be validated. */ protected function validateAllValues(array $ignore = []): array { $out = []; if (!\in_array('country', $ignore)) { try { $this->validateValue('country', Country::make(Utils::getRawProperty($this, 'country'))); } catch (\TypeError | \BadMethodCallException $e) { // Use this to throw validation error. $this->validateValue('country', Utils::getRawProperty($this, 'country')); } $out['country'] = Utils::getRawProperty($this, 'country'); } return array_merge($out, parent::validateAllValues(array_merge(['country'], $ignore))); } // * PUBLIC METHODS /** * Find a customer using its hashcode in the crm * * @param string $hashcode * @return self|null Return null if the customer was not found * @throws \LDC\LDCCRM\Exceptions\CrmException If an error occurs on server side or on getting response. * @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs. * @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber */ public static function find(string $hashcode): ?self { static::setUpApiInterface(); $request = Utils::getResquest('apiV2.customers.show', [ 'serviceCustomer' => $hashcode ]); $customer = null; try { $response = static::$apiInterface->call($request); $customer = new self(); // ! Use fillRaw here because we cant validate comming // ! from CRM since it has crappy data comming from the old crm (jellix). $customer->fillRaw($response->data); Utils::setRawProperty($customer, 'isNew', false); } catch (ApiErrorException $e) { if (!$e->getApiError()->equals(ApiError::modelNotFound())) { throw $e; } } return $customer; } /** * Find a customer using its email in the crm * This is an alias of Customer::find() * * @param string $email * @return self|null * @throws \LDC\LDCCRM\Exceptions\CrmException If an error occurs on server side or on getting response. * @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs. * @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber */ public static function findWithEmail(string $email): ?self { return static::find($email); } /** * Save the customer on CRM. * * @return boolean True if save was successfull. * @throws \LDC\LDCCRM\Exceptions\ValidationException If a field could not be validated. * @throws \LDC\LDCCRM\Exceptions\CrmException If an error occurs on server side or on getting response. * @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs. * Possibles are : - validationFailed, If provided data is wrong(CRM side). * - modelNotFound, If this customer hashcode could not be found (new customers only). * @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber */ public function save(): bool { $saved = false; if ($this->isNew) { $saved = $this->store(); $this->isNew = !$saved; $this->updatedValues = []; if ($saved) { Utils::setRawProperty($this, 'password', null); } return $saved; } else { if (empty($this->updatedValues)) { return true; } if ($saved = $this->update()) { $this->updatedValues = []; Utils::setRawProperty($this, 'password', null); } } return $saved; } /** * Calls api store customer method * * @return boolean True if save was successfull. * @throws \LDC\LDCCRM\Exceptions\ValidationException If a field could not be validated. * @throws \LDC\LDCCRM\Exceptions\CrmException If an error occurs on server side or on getting response. * @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs. * Possibles are : - validationFailed, If provided data is wrong(CRM side). * @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber */ private function store(): bool { $data = $this->validateAllValues(['hashcode', 'last_connection', 'status']); $data['password'] = $this->password; static::setUpApiInterface(); $request = Utils::getResquest('apiV2.customers.store', [], $data); $response = static::$apiInterface->call($request); if ($status = $response->status->equals(ApiStatus::OK())) { $this->updatedValues = []; $this->fill($response->data); } return $status; } /** * Calls api update customer method * * @return boolean True if save was successfull. * @throws \LDC\LDCCRM\Exceptions\ValidationException If a field could not be validated. * @throws \LDC\LDCCRM\Exceptions\CrmException If an error occurs on server side or on getting response. * @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs. * Possibles are : - validationFailed, If provided data is wrong(CRM side). * - modelNotFound, If this customer hashcode could not be found. * @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber */ private function update(): bool { $this->validateValue('hashcode', $this->hashcode); static::setUpApiInterface(); $request = Utils::getResquest('apiV2.customers.update', [ 'serviceCustomer' => $this->hashcode ], $this->updatedValues); $response = static::$apiInterface->call($request); if ($status = $response->status->equals(ApiStatus::OK())) { $this->updatedValues = []; $this->fill($response->data); } return $status; } /** * Removes the customer from CRM. * * @return boolean true if succeeded * @throws \LDC\LDCCRM\Exceptions\ValidationException If a field could not be validated. * @throws \LDC\LDCCRM\Exceptions\CrmException If an error occurs on server side or on getting response. * @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs. * Possibles are : - modelNotFound, If this customer hashcode could not be found. * @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber */ public function delete(): bool { $this->validateValue('hashcode', $this->hashcode); static::setUpApiInterface(); $request = Utils::getResquest('apiV2.customers.destroy', [ 'serviceCustomer' => $this->hashcode ]); $response = static::$apiInterface->call($request); return $response->status->equals(ApiStatus::OK()); } /** * Active the customer on CRM. * * @return boolean true if succeeded * @throws \LDC\LDCCRM\Exceptions\ValidationException If a customer's hashcode could not be validated. * @throws \LDC\LDCCRM\Exceptions\CrmException If an error occurs on server side or on getting response. * @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs. * Possibles are : - modelNotFound, If this customer hashcode could not be found. * - customerAlreadyActive, It the customer is already activated. * @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber */ public function activate(): bool { $this->validateValue('hashcode', $this->hashcode); static::setUpApiInterface(); $request = Utils::getResquest('apiV2.customers.activate', [ 'serviceCustomer' => $this->hashcode ]); $response = static::$apiInterface->call($request); $this->__set('status', true); return $response->status->equals(ApiStatus::OK()); } /** * Toggle the account optin value in the crm * * @return boolean true if succeeded * @throws \LDC\LDCCRM\Exceptions\ValidationException If a field could not be validated. * @throws \LDC\LDCCRM\Exceptions\CrmException If an error occurs on server side or on getting response. * @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs. * Possibles are : - modelNotFound, If this customer hashcode could not be found. * @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber */ public function toggleOptin(): bool { $this->__set('opt_in', !$this->opt_in); return $this->update(); } /** * Test customer credentials * * @param string $email * @param string $password * @return boolean * @throws \LDC\LDCCRM\Exceptions\ValidationException If a customer's email could not be validated. * @throws \LDC\LDCCRM\Exceptions\CrmException If an error occurs on server side or on getting response. * @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs. * Possibles are : - authFailed, If credentials are not valid. * - customerNotActivated, If the account is not activated. * @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber */ public static function login(string $email, string $password): bool { self::validateValue('email', $email); static::setUpApiInterface(); $request = Utils::getResquest('apiV2.customers.authenticate', [], [ 'email' => $email, 'password' => $password ]); $response = static::$apiInterface->call($request); return $response->status->equals(ApiStatus::OK()); } /** * Serialize this object to an array * * @return array */ public function jsonSerialize() { return [ 'hashcode' => $this->hashcode, 'email' => $this->email, 'firstname' => $this->firstname, 'lastname' => $this->lastname, 'birth_date' => $this->birth_date, 'phone' => $this->phone, 'address' => $this->address, 'address2' => $this->address2, 'city' => $this->city, 'postcode' => $this->postcode, 'country' => $this->country, 'opt_in' => $this->opt_in, 'status' => $this->status, 'last_connection' => $this->last_connection ]; } }