2021-08-09 09:18:46 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace LDC\LDCCRM\Models;
|
|
|
|
|
|
|
|
|
|
use LDC\LDCCRM\Enums\ApiError;
|
|
|
|
|
use LDC\LDCCRM\Enums\ApiStatus;
|
|
|
|
|
use LDC\LDCCRM\Enums\Country;
|
|
|
|
|
use LDC\LDCCRM\Exceptions\ApiErrorException;
|
|
|
|
|
use LDC\LDCCRM\Utils;
|
|
|
|
|
use TypeError;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This class represents the customer info with
|
|
|
|
|
* the account validation status. You can use it as
|
|
|
|
|
* a standalone class but beware of catching exceptions
|
|
|
|
|
*
|
|
|
|
|
* @property string $hashcode The crm hashcode this is a readonly field
|
|
|
|
|
* @property string $email Must be a rfc valid email on a valid domain name
|
2021-08-09 11:41:02 +02:00
|
|
|
* @property string $password Required only on create, must have upper and lowers chars,
|
|
|
|
|
* at least 1 number, at leat 1 upper char, at least 1 lower char and
|
|
|
|
|
* at leat 1 special char
|
2021-08-09 09:18:46 +02:00
|
|
|
* @property string $firstname The account first name
|
|
|
|
|
* @property string $lastname The account last name
|
|
|
|
|
* @property string $birth_date The account birth date 'yyyy-mm-dd'
|
|
|
|
|
* @property string $phone The account phone
|
|
|
|
|
* @property string $address The account address (street number, name, build, flat number)
|
|
|
|
|
* @property string $address2 The account phone (address complement)
|
|
|
|
|
* @property string $city The account city name
|
|
|
|
|
* @property string $postcode The account city postcode
|
|
|
|
|
* @property \LDC\LDCCRM\Enums\Country $country The account country residence
|
|
|
|
|
* @property bool $opt_in true if the account is opt in
|
|
|
|
|
* @property bool $status true if the account is activated
|
|
|
|
|
* @property string $last_connection the last time user was connected 'yyyy-mm-dd HH:ii:ss'
|
|
|
|
|
*
|
|
|
|
|
* @example examples/CustomerExample.php
|
|
|
|
|
*
|
|
|
|
|
* @category Api Models
|
|
|
|
|
* @package LDCCrmClient
|
|
|
|
|
* @subpackage models
|
|
|
|
|
*/
|
|
|
|
|
class Customer extends CrmClientModel
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Is true if this model was not filled from crm
|
|
|
|
|
*
|
|
|
|
|
* @var boolean
|
|
|
|
|
*/
|
|
|
|
|
private $isNew = true;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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
|
|
|
|
|
*
|
2021-08-09 11:41:02 +02:00
|
|
|
* Validate: case_diff,numbers,letters,symbols,min:8
|
2021-08-09 09:18:46 +02:00
|
|
|
*
|
2021-08-09 11:41:02 +02:00
|
|
|
* Min length 8
|
2021-08-09 09:18:46 +02:00
|
|
|
* 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: string
|
|
|
|
|
*
|
|
|
|
|
* Required
|
|
|
|
|
* 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
|
|
|
|
|
*
|
|
|
|
|
* Required
|
|
|
|
|
* Min length NA
|
|
|
|
|
* Max length 255
|
|
|
|
|
* Field Type varchar
|
|
|
|
|
*
|
|
|
|
|
* @var string
|
|
|
|
|
*/
|
|
|
|
|
private $address2 = null;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The user address city
|
|
|
|
|
*
|
|
|
|
|
* Validate: string
|
|
|
|
|
*
|
|
|
|
|
* Required
|
|
|
|
|
* 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
|
|
|
|
|
* TODO: change this crm field to TinyInt when CRMV1 is dropped
|
|
|
|
|
* Field Type varchar (for now)
|
|
|
|
|
*
|
|
|
|
|
* @var \LDC\LDCCRM\Enums\Country
|
|
|
|
|
*/
|
|
|
|
|
private $country = null;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The user optin choice
|
|
|
|
|
*
|
|
|
|
|
* Validate: boolean
|
|
|
|
|
*
|
|
|
|
|
* Required
|
|
|
|
|
* Field Type TinyInt
|
|
|
|
|
*
|
|
|
|
|
* @var bool
|
|
|
|
|
*/
|
|
|
|
|
private $opt_in = false;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Is the account activated ?
|
|
|
|
|
*
|
|
|
|
|
* This field is read only
|
|
|
|
|
*
|
|
|
|
|
* @var bool
|
|
|
|
|
*/
|
|
|
|
|
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:rfc,dns,spoof,filter',
|
|
|
|
|
'firstname' => 'required|string|min:2|max:255',
|
|
|
|
|
'lastname' => 'required|string|min:2|max:255',
|
2021-08-09 11:41:02 +02:00
|
|
|
'password' => 'required|min:8|max:255',
|
2021-08-09 09:18:46 +02:00
|
|
|
'birth_date' => 'required|date_format:Y-m-d',
|
|
|
|
|
'phone' => 'sometimes|string|min:10|max:255',
|
|
|
|
|
'address' => 'required|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
|
|
|
|
|
*/
|
|
|
|
|
public static function find(string $hashcode): ?self
|
|
|
|
|
{
|
|
|
|
|
static::setUpApiInterface(); // set apiInterface
|
2021-08-11 17:26:30 +02:00
|
|
|
$request = Utils::getResquest('apiV2.customers.show', [
|
2021-08-09 09:18:46 +02:00
|
|
|
'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
|
|
|
|
|
*/
|
|
|
|
|
public static function findWithEmail(string $email): ?self
|
|
|
|
|
{
|
|
|
|
|
return static::find($email);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Save the actual account in the crm
|
|
|
|
|
*
|
|
|
|
|
* @return boolean true if succeeded
|
|
|
|
|
*/
|
|
|
|
|
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
|
2021-08-11 17:26:30 +02:00
|
|
|
$request = Utils::getResquest('apiV2.customers.store', [], $data);
|
2021-08-09 09:18:46 +02:00
|
|
|
|
|
|
|
|
$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
|
2021-08-11 17:26:30 +02:00
|
|
|
$request = Utils::getResquest('apiV2.customers.update', [
|
2021-08-09 09:18:46 +02:00
|
|
|
'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
|
|
|
|
|
*/
|
|
|
|
|
public function delete(): bool
|
|
|
|
|
{
|
|
|
|
|
$this->validateValue('hashcode', $this->hashcode);
|
|
|
|
|
static::setUpApiInterface(); // set apiInterface
|
2021-08-11 17:26:30 +02:00
|
|
|
$request = Utils::getResquest('apiV2.customers.destroy', [
|
2021-08-09 09:18:46 +02:00
|
|
|
'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
|
|
|
|
|
*/
|
|
|
|
|
public function activate(): bool
|
|
|
|
|
{
|
|
|
|
|
$this->validateValue('hashcode', $this->hashcode);
|
|
|
|
|
static::setUpApiInterface(); // set apiInterface
|
2021-08-11 17:26:30 +02:00
|
|
|
$request = Utils::getResquest('apiV2.customers.activate', [
|
2021-08-09 09:18:46 +02:00
|
|
|
'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
|
|
|
|
|
*/
|
|
|
|
|
public function toggleOptin(): bool
|
|
|
|
|
{
|
|
|
|
|
$this->opt_in = !$this->opt_in;
|
|
|
|
|
return $this->update();
|
|
|
|
|
}
|
|
|
|
|
}
|