'required|uuid', 'email' => 'required|email', 'firstname' => 'required|string|min:2|max:255', 'lastname' => 'required|string|min:2|max:255', 'password' => 'required|min:8|max:255', 'birth_date' => 'required|date_format:Y-m-d', 'phone' => 'sometimes|string|min:10|max:255', 'address' => 'sometimes|string|max:255', 'address2' => 'sometimes|string|max:255', 'city' => 'required|string|max:255', 'postcode' => 'required|string|max:255', 'country' => ['sometimes'], 'opt_in' => 'required|bool', 'status' => 'required|bool', 'last_connection' => 'sometimes|date' ]; public function __construct(array $properties = []) { parent::__construct(); if (!is_array(self::$validation['password'])) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed self::$validation['country'][] = function ($attribute, $value, $fail) { if (!is_object($value) or !\in_array($value, Country::toArray())) { $type = \gettype($value); $fail("Country ($type)$value is not in Country enum list"); } }; self::$validation['password'] = array_merge(explode('|', self::$validation['password']), [ // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed,Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed function ($attribute, $value, $fail) { if (!\preg_match('/[a-z]/', $value) or !\preg_match('/[A-Z]/', $value)) { $fail('The password must contain uppercase and lowercase chars.'); } if (!\preg_match('/[0-9]/', $value)) { $fail('The password must contain numbers.'); } if (!\preg_match('/[^\w]/', $value)) { $fail('The password must contain symbols.'); } } ]); } $this->fill($properties); return $this; } 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 * * @param string $field * @param mixed $value * @throws TypeError if the field has an incorrect value * @return mixed|null The input value or null is this prop does not exists */ public function __set(string $field, $value) { $out = parent::__set($field, $value); if (in_array($field, $this->modelFields)) { $this->updatedValues[$field] = (\is_object($value) and get_class($value) === Country::class) ? $value->value : $value; $this->setRawProperty($this, $field, $this->updatedValues[$field]); } return $out; } /** * Fill data into this model * using validation rules * * @param array $properties * @return void * @throws TypeError if any valid is not validated */ public function fill(array $properties) { if (isset($properties['country'])) { try { $properties['country'] = (\is_int($properties['country']) or \ctype_digit($properties['country'])) ? Country::make((int)$properties['country']) : $properties['country']; } catch (TypeError $e) { // cast anyway $properties['country'] = (int)$properties['country']; } } parent::fill($properties); } /** * Validate all model properties * * @return array the validated values */ protected function validateAllValues(array $ignore = []): array { $out = []; if (!\in_array('country', $ignore)) { try { $this->validateValue('country', Country::make(self::getRawProperty($this, 'country'))); } catch (TypeError $e) { // this to throw validation error if failure way $this->validateValue('country', self::getRawProperty($this, 'country')); } $out['country'] = self::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 * @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 */ public static function find(string $hashcode): ?self { static::setUpApiInterface(); // set apiInterface $request = Utils::getResquest('apiV2.customers.show', [ 'customer' => $hashcode ]); $customer = null; try { $response = static::$apiInterface->call($request); $customer = new self(); $customer->fillRaw($response->data); static::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 */ public static function findWithEmail(string $email): ?self { return static::find($email); } /** * Save the actual account in the crm * * @return boolean true if succeeded * @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 */ public function save(): bool { $saved = false; if ($this->isNew) { $saved = $this->store(); $this->isNew = !$saved; $this->updatedValues = []; if ($saved) { $this->setRawProperty($this, 'password', null); } return $saved; } if ($saved = $this->update()) { $this->updatedValues = []; $this->setRawProperty($this, 'password', null); } return $saved; } private function store(): bool { $data = $this->validateAllValues(['hashcode', 'last_connection', 'status']); $data['password'] = $this->password; static::setUpApiInterface(); // set apiInterface $request = Utils::getResquest('apiV2.customers.store', [], $data); $response = static::$apiInterface->call($request); if ($status = $response->status->equals(ApiStatus::OK())) { $this->updatedValues = []; } return $status; } private function update(): bool { $this->validateValue('hashcode', $this->hashcode); static::setUpApiInterface(); // set apiInterface $request = Utils::getResquest('apiV2.customers.update', [ 'customer' => $this->hashcode ], $this->updatedValues); $response = static::$apiInterface->call($request); if ($status = $response->status->equals(ApiStatus::OK())) { $this->updatedValues = []; } return $status; } /** * Delete the actual account in the crm * * @return boolean true if succeeded * @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 */ public function delete(): bool { $this->validateValue('hashcode', $this->hashcode); static::setUpApiInterface(); // set apiInterface $request = Utils::getResquest('apiV2.customers.destroy', [ 'customer' => $this->hashcode ]); $response = static::$apiInterface->call($request); return $response->status->equals(ApiStatus::OK()); } /** * Activate the account in the crm * * @return boolean true if succeeded * @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 */ public function activate(): bool { $this->validateValue('hashcode', $this->hashcode); static::setUpApiInterface(); // set apiInterface $request = Utils::getResquest('apiV2.customers.activate', [ 'customer' => $this->hashcode ]); $response = static::$apiInterface->call($request); $this->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\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 */ public function toggleOptin(): bool { $this->opt_in = !$this->opt_in; return $this->update(); } /** * Test customer credentials * * @param string $email * @param string $password * @return boolean * @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 */ public static function login(string $email, string $password): bool { self::validateValue('email', $email); static::setUpApiInterface(); // set apiInterface $request = Utils::getResquest('apiV2.customers.authenticate', [], [ 'email' => $email, 'password' => $password ]); try { $response = static::$apiInterface->call($request); } catch (ApiErrorException $e) { if ($e->getApiError()->equals(ApiError::authFailed())) { return false; } /** * 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 ]; } }