# easy-invoice/2.3.7/includes/Models/Client.php

Easy Invoice – Invoice Generator, PDF Quotes &amp; Payments, version 2.3.7. 226 lines.

- Page: https://pluginprobe.com/plugins/easy-invoice/2.3.7/code/includes/Models/Client.php
- Raw: https://pluginprobe.com/plugins/easy-invoice/2.3.7/raw/includes/Models/Client.php
- Modified: 2026-05-24T14:33:32+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/easy-invoice/2.3.7/code/includes/Models/Client.php#L10-L20`.

```php
<?php
/**
 * Client Model Class
 *
 * @package Easy_Invoice
 * @subpackage Models
 */

namespace EasyInvoice\Models;

use EasyInvoice\Constants\ClientFields;

/**
 * Client Class
 * 
 * Represents a client entity.
 */
class Client {
    /**
     * The client ID (WP user ID)
     *
     * @var int
     */
    protected $id = 0;
    
    /**
     * Client data array
     *
     * @var array
     */
    protected $data = [];
    
    /**
     * Whether the data is dirty/changed
     *
     * @var bool
     */
    protected $is_dirty = false;
    
    /**
     * Constructor
     *
     * @param int|array $id_or_data The client ID or data array
     */
    public function __construct($id_or_data = 0) {
        if (is_array($id_or_data)) {
            $this->data = $id_or_data;
            $this->id = isset($id_or_data['id']) ? (int) $id_or_data['id'] : 0;
        } else {
            $this->id = (int) $id_or_data;
            // Load data from user meta if we have a valid ID
            if ($this->id > 0) {
                $this->loadFromUserMeta();
            }
        }
    }

    /**
     * Magic method to get dynamic properties
     *
     * @since 1.0.0
     * @param string $name Property name
     * @return mixed Property value
     */
    public function __get($name) {
        // Handle special properties
        if ($name === 'id') {
            return $this->id;
        }
        
        // Return from dynamic data array
        return $this->data[$name] ?? null;
    }

    /**
     * Magic method to set dynamic properties
     *
     * @since 1.0.0
     * @param string $name Property name
     * @param mixed $value Property value
     */
    public function __set($name, $value) {
        // Handle special properties
        if ($name === 'id') {
            $this->id = $value;
            return;
        }
        
        // Store in dynamic data array
        $this->data[$name] = $value;
        $this->is_dirty = true;
    }

    /**
     * Magic method to check if property exists
     *
     * @since 1.0.0
     * @param string $name Property name
     * @return bool
     */
    public function __isset($name) {
        if ($name === 'id') {
            return isset($this->id);
        }
        
        return isset($this->data[$name]);
    }

    /**
     * Dynamic getter method
     *
     * @since 1.0.0
     * @param string $name Method name
     * @param array $arguments Method arguments
     * @return mixed
     */
    public function __call($name, $arguments) {
        // Handle getter methods (getFieldName)
        if (strpos($name, 'get') === 0) {
            $field_name = $this->camelCaseToSnakeCase(substr($name, 3)); // Remove 'get' prefix
            return $this->__get($field_name);
        }
        
        // Handle setter methods (setFieldName)
        if (strpos($name, 'set') === 0) {
            $field_name = $this->camelCaseToSnakeCase(substr($name, 3)); // Remove 'set' prefix
            $value = $arguments[0] ?? null;
            $this->__set($field_name, $value);
            return null;
        }
        
        // Handle isset methods (isFieldName)
        if (strpos($name, 'is') === 0) {
            $field_name = $this->camelCaseToSnakeCase(substr($name, 2)); // Remove 'is' prefix
            return (bool) $this->__get($field_name);
        }
        
        // Handle has methods (hasFieldName)
        if (strpos($name, 'has') === 0) {
            $field_name = $this->camelCaseToSnakeCase(substr($name, 3)); // Remove 'has' prefix
            return !empty($this->__get($field_name));
        }
        
        throw new \BadMethodCallException("Method $name does not exist");
    }

    /**
     * Convert camelCase to snake_case
     *
     * @since 1.0.0
     * @param string $camelCase
     * @return string
     */
    private function camelCaseToSnakeCase($camelCase) {
        return strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $camelCase));
    }
    
    /**
     * Load client data from user meta
     */
    protected function loadFromUserMeta() {
        if ($this->id <= 0) {
            return;
        }

        // Easy-Invoice-owned meta (what the user explicitly set through this plugin).
        $this->data['business_client_name'] = get_user_meta($this->id, ClientFields::BUSINESS_CLIENT_NAME, true);
        $this->data['email']                = get_user_meta($this->id, ClientFields::EMAIL, true);
        $this->data['username']             = get_user_meta($this->id, ClientFields::USERNAME, true);
        $this->data['address']              = get_user_meta($this->id, ClientFields::ADDRESS, true);
        $this->data['extra_info']           = get_user_meta($this->id, ClientFields::EXTRA_INFO, true);
        $this->data['first_name']           = get_user_meta($this->id, ClientFields::FIRST_NAME, true);
        $this->data['last_name']            = get_user_meta($this->id, ClientFields::LAST_NAME, true);
        $this->data['website']              = get_user_meta($this->id, ClientFields::WEBSITE, true);
        $this->data['phone']                = get_user_meta($this->id, ClientFields::PHONE, true);

        // Fallback chain for clients NOT created through Easy Invoice
        // (typically WooCommerce customers imported via order placement,
        // or plain WP users with profile fields filled in):
        //
        //   1. EI meta (above)  — explicit entry in Easy Invoice
        //   2. WP standard meta — user profile / WC sync
        //   3. WC billing_* meta — set the first time a customer checks out
        //
        // Without this fallback, WooCommerce customers render as their bare
        // user_login (e.g. "callum_smith42") everywhere — Clients listing,
        // invoice builder client-search dropdown, and invoice header — even
        // though their real name sits in billing_first_name / billing_last_name.
        $user = get_user_by('id', $this->id);

        if (empty($this->data['email'])) {
            $this->data['email'] = $user ? (string) $user->user_email : '';
            if (empty($this->data['email'])) {
                $this->data['email'] = (string) get_user_meta($this->id, 'billing_email', true);
            }
        }
        if (empty($this->data['username'])) {
            $this->data['username'] = $user ? (string) $user->user_login : '';
        }
        if (empty($this->data['first_name'])) {
            $this->data['first_name'] = $user ? (string) $user->first_name : '';
            if (empty($this->data['first_name'])) {
                $this->data['first_name'] = (string) get_user_meta($this->id, 'billing_first_name', true);
            }
        }
        if (empty($this->data['last_name'])) {
            $this->data['last_name'] = $user ? (string) $user->last_name : '';
            if (empty($this->data['last_name'])) {
                $this->data['last_name'] = (string) get_user_meta($this->id, 'billing_last_name', true);
            }
        }
        if (empty($this->data['business_client_name'])) {
            $this->data['business_client_name'] = (string) get_user_meta($this->id, 'billing_company', true);
        }
        if (empty($this->data['phone'])) {
            $this->data['phone'] = (string) get_user_meta($this->id, 'billing_phone', true);
        }
    }
    
    // Essential methods only
    public function getId(): int { return $this->id; }
    public function setId(int $id): void { $this->id = $id; }
    public function isDirty(): bool { return $this->is_dirty; }
    public function resetDirty() { $this->is_dirty = false; return $this; }
    public function toArray(): array { return array_merge(['id' => $this->id], $this->data); }
} 
```
