Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/pod.git
<?php
class Address {
  private $fields = [];
  private $missing = [];
  private const NOOP = false;
  private const UPPER = true;

  private const REGION_MAP = [
    // Australia
    'NEWSOUTHWALES' => 'NSW',
    'VICTORIA' => 'VIC',
    'QUEENSLAND' => 'QLD',
    'WESTERNAUSTRALIA' => 'WA',
    'SOUTHAUSTRALIA' => 'SA',
    'TASMANIA' => 'TAS',
    'AUSTRALIANCAPITALTERRITORY' => 'ACT',
    'NORTHERNTERRITORY' => 'NT',
    // Canada
    'ALBERTA' => 'AB',
    'BRITISHCOLUMBIA' => 'BC',
    'MANITOBA' => 'MB',
    'NEWBRUNSWICK' => 'NB',
    'NEWFOUNDLAND' => 'NL',
    'NEWFOUNDLANDANDLABRADOR' => 'NL',
    'NORTHWESTTERRITORIES' => 'NT',
    'NOVASCOTIA' => 'NS',
    'NUNAVUT' => 'NU',
    'ONTARIO' => 'ON',
    'PRINCEEDWARDISLAND' => 'PE',
    'PEI' => 'PE',
    'QUEBEC' => 'QC',
    'QB' => 'QC',
    'SASKATCHEWAN' => 'SK',
    'YUKON' => 'YT',
    // United States
    'ALABAMA' => 'AL',
    'ALASKA' => 'AK',
    'ARIZONA' => 'AZ',
    'ARKANSAS' => 'AR',
    'CALIFORNIA' => 'CA',
    'COLORADO' => 'CO',
    'CONNECTICUT' => 'CT',
    'DELAWARE' => 'DE',
    'DISTRICTOFCOLUMBIA' => 'DC',
    'FLORIDA' => 'FL',
    'GEORGIA' => 'GA',
    'HAWAII' => 'HI',
    'IDAHO' => 'ID',
    'ILLINOIS' => 'IL',
    'INDIANA' => 'IN',
    'IOWA' => 'IA',
    'KANSAS' => 'KS',
    'KENTUCKY' => 'KY',
    'LOUISIANA' => 'LA',
    'MAINE' => 'ME',
    'MARYLAND' => 'MD',
    'MASSACHUSETTS' => 'MA',
    'MICHIGAN' => 'MI',
    'MINNESOTA' => 'MN',
    'MISSISSIPPI' => 'MS',
    'MISSOURI' => 'MO',
    'MONTANA' => 'MT',
    'NEBRASKA' => 'NE',
    'NEVADA' => 'NV',
    'NEWHAMPSHIRE' => 'NH',
    'NEWJERSEY' => 'NJ',
    'NEWMEXICO' => 'NM',
    'NEWYORK' => 'NY',
    'NORTHCAROLINA' => 'NC',
    'NORTHDAKOTA' => 'ND',
    'OHIO' => 'OH',
    'OKLAHOMA' => 'OK',
    'OREGON' => 'OR',
    'PENNSYLVANIA' => 'PA',
    'RHODEISLAND' => 'RI',
    'SOUTHCAROLINA' => 'SC',
    'SOUTHDAKOTA' => 'SD',
    'TENNESSEE' => 'TN',
    'TEXAS' => 'TX',
    'UTAH' => 'UT',
    'VERMONT' => 'VT',
    'VIRGINIA' => 'VA',
    'WASHINGTON' => 'WA',
    'WESTVIRGINIA' => 'WV',
    'WISCONSIN' => 'WI',
    'WYOMING' => 'WY'
  ];

  /**
   * Initializes and automatically validates the address.
   *
   * @param array $input Raw address field data.
   */
  public function __construct( array $input ) {
    $this->fields = $input;
    $this->process();
  }

  /**
   * Validates required fields, normalizes data, and converts state names
   * to abbreviations.
   *
   * @param array $required Field names that must be present.
   *
   * @return bool True if all required fields are present, false otherwise.
   */
  public function process( array $required = [] ): bool {
    foreach( $required as $field ) {
      if( empty( $this->fields[ $field ] ) ) {
        $this->missing[] = $field;
      }
    }

    $rules = [
      'name'     => [ 100, self::NOOP  ],
      'street1'  => [ 100, self::UPPER ],
      'street2'  => [ 100, self::UPPER ],
      'city'     => [ 50,  self::UPPER ],
      'state'    => [ 50,  self::UPPER ],
      'postcode' => [ 20,  self::UPPER ],
      'country'  => [ 2,   self::UPPER ],
      'phone'    => [ 20,  self::NOOP  ],
      'email'    => [ 254, self::NOOP  ],
      'gifted'   => [ 100, self::NOOP  ]
    ];

    $clean = [];

    foreach( $rules as $field => $config ) {
      $value = mb_substr( trim( $this->fields[ $field ] ?? '' ), 0,
        $config[ 0 ], 'UTF-8' );

      $transform = [
        self::NOOP  => $value,
        self::UPPER => mb_strtoupper( $value, 'UTF-8' )
      ];

      $finalValue = $transform[ $config[ 1 ] ];

      if ( $field === 'state' ) {
        $lookup = str_replace( ' ', '', $finalValue );
        $finalValue = self::REGION_MAP[ $lookup ] ?? $finalValue;
      }

      $clean[ $field ] = $finalValue;
    }

    $this->fields = $clean;

    return empty( $this->missing );
  }

  /**
   * Saves the validated address to the session if all required fields
   * are present.
   *
   * @param Session $session Session object to store the address data.
   */
  public function export( Session $session ) {
    if( empty( $this->missing ) ) {
      $session->write( 'user_address', $this->fields );
    }
  }

  /**
   * Populates the shipping address section of the API payload with
   * address fields.
   *
   * @param array &$payload API request payload to modify by reference.
   *
   * @return string The country code from the address fields.
   */
  public function configure( array &$payload ) {
    $payload[ 'shipping_address' ] = [
      'phone_number' => $this->fields[ 'phone' ] ?? '',
      'name'         => $this->fields[ 'name' ] ?? '',
      'email'        => $this->fields[ 'email' ] ?? '',
      'city'         => $this->fields[ 'city' ] ?? '',
      'country_code' => $this->fields[ 'country' ] ?? '',
      'postcode'     => $this->fields[ 'postcode' ] ?? '',
      'state_code'   => $this->fields[ 'state' ] ?? '',
      'street1'      => $this->fields[ 'street1' ] ?? '',
      'street2'      => $this->fields[ 'street2' ] ?? ''
    ];

    return $this->fields[ 'country' ] ?? '';
  }

  /**
   * Outputs an HTML list of missing required fields for display to the
   * user.
   */
  public function render() {
    if( !$this->isComplete() ) {
      echo "<h2>Missing fields</h2><ul>";

      foreach( $this->missing as $field ) {
        echo "<li>" . $this->escape( $field ) . "</li>";
      }

      echo "</ul>";
    }
  }

  /**
   * Checks if a specific field matches an expected value.
   *
   * @param string $field The field name to check.
   * @param string $value The expected value to compare against.
   *
   * @return bool True if the field value matches the expected value.
   */
  public function isField( $field, $value ) {
    return ($this->fields[ $field ] ?? '') === $value;
  }

  /**
   * Checks if all required fields are present and the address is complete.
   *
   * @return bool True if there are no missing required fields.
   */
  public function isComplete() {
    return empty( $this->missing );
  }

  private function escape( $value ) {
    return htmlspecialchars( $value ?? '', ENT_QUOTES, 'UTF-8' );
  }
}