0 ) ? $userId : null; $this->id = $id; $this->userId = $linkedUserId; $this->email = $normalizedEmail; $this->name = ( null === $name || '' === $name ) ? null : $name; $this->firstName = self::blankToNull( $firstName ); $this->lastName = self::blankToNull( $lastName ); $this->purchaseCount = max( 0, $purchaseCount ); $this->purchaseTotal = $purchaseTotal; $this->createdAt = $createdAt; $this->updatedAt = $updatedAt; } /** * Trim a value and return null if it is empty. * * @since 1.0.0 * * @param string|null $value The raw value. * @return string|null The trimmed value, or null when blank. */ private static function blankToNull( ?string $value ): ?string { if ( null === $value ) { return null; } $trimmed = trim( $value ); return '' === $trimmed ? null : $trimmed; } /** * Build a customer from input data with guest defaults. * * @since 1.0.0 * * @param array $data Scalar fields keyed by column name. * @return self * * @throws CustomerException When the email is empty or malformed. */ public static function fromArray( array $data ): self { return new self( isset( $data['id'] ) ? (int) $data['id'] : null, isset( $data['user_id'] ) && null !== $data['user_id'] ? (int) $data['user_id'] : null, (string) ( $data['email'] ?? '' ), isset( $data['name'] ) && null !== $data['name'] ? (string) $data['name'] : null, (int) ( $data['purchase_count'] ?? 0 ), (int) ( $data['purchase_total'] ?? 0 ), isset( $data['created_at'] ) && null !== $data['created_at'] ? (string) $data['created_at'] : null, isset( $data['updated_at'] ) && null !== $data['updated_at'] ? (string) $data['updated_at'] : null, isset( $data['first_name'] ) && null !== $data['first_name'] ? (string) $data['first_name'] : null, isset( $data['last_name'] ) && null !== $data['last_name'] ? (string) $data['last_name'] : null ); } /** * Build a customer from a database row. * * @since 1.0.0 * * @param object $row A `releasecart_customers` row. * @return self * * @throws CustomerException When the stored email is malformed. */ public static function fromRow( object $row ): self { return self::fromArray( (array) $row ); } /** * Return repository columns without IDs or timestamps. * * A guest has a null user ID, so the unique index does not match another guest. * * @since 1.0.0 * * @return array Column name => value. */ public function toRow(): array { return array( 'user_id' => $this->userId, 'email' => $this->email, 'name' => $this->name, 'first_name' => $this->firstName, 'last_name' => $this->lastName, 'purchase_count' => $this->purchaseCount, 'purchase_total' => $this->purchaseTotal, ); } /** * Trim and lowercase an email for comparisons. * * @since 1.0.0 * * @param string $email The raw email address. * @return string The normalized email. */ public static function normalizeEmail( string $email ): string { return strtolower( trim( $email ) ); } /** * The primary key, or null when unsaved. * * @since 1.0.0 * * @return int|null */ public function id(): ?int { return $this->id; } /** * The linked WordPress user id, or null for a guest. * * @since 1.0.0 * * @return int|null */ public function userId(): ?int { return $this->userId; } /** * The normalized email address. * * @since 1.0.0 * * @return string */ public function email(): string { return $this->email; } /** * The display name, or null. * * @since 1.0.0 * * @return string|null */ public function name(): ?string { return $this->name; } /** * The given name, or null. * * @since 1.0.0 * * @return string|null */ public function firstName(): ?string { return $this->firstName; } /** * The family name, or null. * * @since 1.0.0 * * @return string|null */ public function lastName(): ?string { return $this->lastName; } /** * The denormalized completed-purchase count. * * @since 1.0.0 * * @return int */ public function purchaseCount(): int { return $this->purchaseCount; } /** * The denormalized lifetime spend in minor units. * * @since 1.0.0 * * @return int */ public function purchaseTotal(): int { return $this->purchaseTotal; } /** * The UTC creation timestamp, or null. * * @since 1.0.0 * * @return string|null */ public function createdAt(): ?string { return $this->createdAt; } /** * The UTC last-update timestamp, or null. * * @since 1.0.0 * * @return string|null */ public function updatedAt(): ?string { return $this->updatedAt; } /** * Whether this customer is a guest (no linked WordPress user account). * * @since 1.0.0 * * @return bool */ public function isGuest(): bool { return null === $this->userId; } /** * Whether this customer is linked to a WordPress user account. * * @since 1.0.0 * * @return bool */ public function isLinked(): bool { return null !== $this->userId; } }