Location: PHPKode > projects > Sierra-php PHP Application Framework > sierra/lib/util/l10n/SRA_AddressFormat.php
<?php
// {{{ Header
/*
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
 | SIERRA : PHP Application Framework  http://code.google.com/p/sierra-php |
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
 | Copyright 2005 Jason Read                                               |
 |                                                                         |
 | Licensed under the Apache License, Version 2.0 (the "License");         |
 | you may not use this file except in compliance with the License.        |
 | You may obtain a copy of the License at                                 |
 |                                                                         |
 |     http://www.apache.org/licenses/LICENSE-2.0                          |
 |                                                                         |
 | Unless required by applicable law or agreed to in writing, software     |
 | distributed under the License is distributed on an "AS IS" BASIS,       |
 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.|
 | See the License for the specific language governing permissions and     |
 | limitations under the License.                                          |
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
 */
// }}}

// {{{ Constants
/**
 * the name of the properties file containing the ISO 3166 country code/names
 * @type String
 */
define('SRA_ADDRESS_FORMAT_COUNTRY_PROPERTIES', 'iso3166');

/**
 * the name of the properties file containing the address field labels
 * @type String
 */
define('SRA_ADDRESS_FORMAT_FIELD_PROPERTIES', 'address-fields');

/**
 * the name of the properties file containing the address field mappings
 * @type String
 */
define('SRA_ADDRESS_FORMAT_FIELD_MAPPING_PROPERTIES', 'address-field-mappings');

/**
 * the max columns for any address format
 * @type int
 */
define('SRA_ADDRESS_FORMAT_MAX_COLS', 3);

/**
 * the max rows for any address format
 * @type int
 */
define('SRA_ADDRESS_FORMAT_MAX_ROWS', 5);

/**
 * the location of the SRA_AddressFormat xml definition file
 * @type String
 */
define('SRA_ADDRESS_FORMAT_XML_DATA_FILE', file_exists(SRA_CONF_DIR . '/l10n/address-formats.xml') ? SRA_CONF_DIR . '/l10n/address-formats.xml' : SRA_CONF_DIR . '/l10n/address-formats-default.xml');
// }}}

// {{{ Includes
require_once('util/l10n/SRA_Country.php');
// }}}

// {{{ SRA_AddressFormat
/**
 * used to represent an country specific address format as defined in 
 * 'sierra/etc/l10n/address-formats.xml'. a single address format consists of 
 * the attributes that make up the address, the labels to use for those 
 * attributes, and the layout to use to display the address. for more 
 * information, review the address api comments below. when imported, a default 
 * instance of this class will be added to the application template using the 
 * variable name 'SRA_AddressFormat'
 * @author Jason Read <hide@address.com>
 * @package sierra.util.l10n
 */
class SRA_AddressFormat {
  // {{{ Properties
  // private
  
  // public
  /**
   * the ISO 3166 country code that this address format pertains to
   * @type String
   */
  var $country;
  
  /**
   * the full country name for this address format as defined by the $country 
   * ISO 3166 country code
   * @type String
   */
  var $countryName;
  
  /**
   * an array of hashes defining the fields that constitute this address 
   * format. each element in this array will be a hash with the following 
   * keys. alternative, the field definitions can be retrieved using the 
   * 'getFieldsAsGrid' method. the keys in this array will be the field ids
   *   id:       the field identifier
   *   attr:     the name of the attribute to use to store this field
   *   col:      the column position within "row" for this field
   *   label:    the field label
   *   options:  a hash of key/value pairs representing the options for this 
   *             field
   *   regex:    a regular expression validation constraint for this field
   *   required: whether or not this field is required
   *   row:      the row position for this field
   * @type array
   */
  var $fields = array();
  
  /**
   * the locale used to initialize this object
   * @type SRA_Locale
   */
  var $locale;
  // }}} 

  // {{{ SRA_AddressFormat
  /**
   * constructor used to instantiate a new address format instance. DO NOT 
   * invoke this method directly. instead, use the static singleton method 
   * "getInstance" below
   * @param String $country the ISO 3166 country code that this address format 
   * pertains to
   * @param object $conf the configuration to use to initialize this address 
   * format as defined in 'sierra/etc/l10n/address-formats.xml'
   * @param SRA_Locale $locale the locale to use in initializing this object
   * @access public
   */
  function SRA_AddressFormat($country, &$conf, &$locale) {
    $this->country = $country;
    $countriesBundle =& SRA_ResourceBundle::getBundle(SRA_ADDRESS_FORMAT_COUNTRY_PROPERTIES, $locale);
    $this->countryName = $countriesBundle->getString($country);
    
    $fields =& SRA_ResourceBundle::getBundle(SRA_ADDRESS_FORMAT_FIELD_PROPERTIES, $locale);
    $fieldMappings =& SRA_ResourceBundle::getBundle(SRA_ADDRESS_FORMAT_FIELD_MAPPING_PROPERTIES, $locale);
    $keys = array_keys($conf['field']);
    foreach($keys as $key) {
      $attrs =& $conf['field'][$key]['attributes'];
      $this->fields[$key] = array('id' => $key, 'attr' => $fieldMappings->getString($key), 
                                  'col' => $attrs['col'] ? $attrs['col'] * 1 : 1, 'label' => $fields->getString($key), 
                                  'required' => isset($attrs['required']) && $attrs['required'] == '1', 
                                  'row' => $attrs['row'] ? $attrs['row'] * 1 : 1,
                                  'showKey' => isset($attrs['show-key']) && $attrs['show-key'] == '1');
      // dynamically add country options
      if ($key == 'country') { 
        $attrs['bundle'] = SRA_ADDRESS_FORMAT_COUNTRY_PROPERTIES;
      }
      if (isset($attrs['bundle']) && SRA_ResourceBundle::isValid($optionsBundle =& SRA_ResourceBundle::getBundle(str_replace('{$country}', strtolower($country), $attrs['bundle']), $locale))) {
        $this->fields[$key]['options'] =& $optionsBundle->getData();
      }
      if (isset($attrs['regex'])) {
        $this->fields[$key]['regex'] = $attrs['regex'];
      }
    }
    $this->locale =& $locale;
  }
  // }}}
  
  // {{{ getFieldsAsGrid
  /**
   * returns the $fields attribute as a grid, or in other words, as a 
   * two-dimensional array where the first level array is the rows and the 
   * second level array is the columns. each element in the columns array will 
   * correspond to one of the $field attributes and will be positioned 
   * correctly according to the 'col' and 'row' definition for that field. the 
   * grid uses 1-based indexing, meaning the first row will resize at $grid[1]
   * @param boolean $skipCountry whether or not to skip the country field
   * @access public
   * @return  array
   */
  function &getFieldsAsGrid($skipCountry=FALSE) {
    $keys = array_keys($this->fields);
    $grid = array();
    for($i=1; $i<=SRA_ADDRESS_FORMAT_MAX_ROWS; $i++) {
      for($n=1; $n<=SRA_ADDRESS_FORMAT_MAX_COLS; $n++) {
        foreach($keys as $key) {
          if ($this->fields[$key]['row'] == $i && $this->fields[$key]['col'] == $n) {
            if (!isset($grid[$i])) { $grid[$i] = array(); }
            $grid[$i][$n] =& $this->fields[$key];
          }
        }
      }
    }
    if ($skipCountry) {
      $rkeys = array_keys($grid);
      foreach($rkeys as $rkey) {
        $ckeys = array_keys($grid[$rkey]);
        foreach($ckeys as $ckey) {
          if ($grid[$rkey][$ckey]['attr'] == 'country') { 
            unset($grid[$rkey][$ckey]);
            break;
          }
        }
      }
    }
    return $grid;
  }
  // }}}
  
  // {{{ getField
  /**
   * returns the field specified by $id
   * @param string $id the field id OR name
   * @access public
   * @return string
   */
  function &getField($id) {
    $field = NULL;
    $keys = array_keys($this->fields);
    foreach($keys as $key) {
      if ($this->fields[$key]['attr'] == $id) {
        $field = &$this->fields[$key];
        break;
      }
    }
    if (!$field) {
      foreach($keys as $key) {
        if ($key == $id) {
          $field = &$this->fields[$key];
          break;
        }
      }
    }
    return $field;
  }
  // }}}
  
  // {{{ getLabel
  /**
   * returns the label to use for the attribute or field id specified
   * @param string $id the id or name of the field to return the label for
   * @access public
   * @return string
   */
  function getLabel($id) {
    return $field =& $this->getField($id) ? $field['label'] : NULL;
  }
  // }}}
  
  // {{{ validateFieldValues
  /**
   * validates field values an returns an array of errors indexed by field id 
   * (if any validation errors  occurred), TRUE if all fields all are valid OR 
   * NULL if the $values parameter is not an array or entity. the value of each 
   * element in the return errors array will be either 'required' or 'regex' 
   * signifying why the field value is not valid (required == field is required 
   * but not specified in $values, and regex == field value failed regex 
   * validation)
   * @param mixed $values the values to validate indexed by field id 
   * (country|locality|postalCode|region|street) OR an entity instance 
   * containing those field values retrievable using the 
   * 'SRA_AddressFormat::getFieldValuesFromEntity' method
   * @access public
   * @return  mixed
   */
  function validateFieldValues(& $values) {
    $fieldValues = method_exists($values, 'isAttribute') ? SRA_AddressFormat::getFieldValuesFromEntity($values) : $values;
    if (is_array($fieldValues)) {
      $errors = array();
      $keys = array_keys($fieldValues);
      foreach($keys as $key) {
        if ($field =& $this->getField($key)) {
          if ($field['required'] && !isset($fieldValues[$key])) {
            $errors[$field['id']] = 'required';
          }
          else if (isset($fieldValues[$key]) && $field['regex'] && !preg_match($field['regex'], $fieldValues[$key])) {
            $errors[$field['id']] = 'regex';
          }
        }
      }
      return count($errors) ? $errors : TRUE;
    }
    else {
      return NULL;
    }
  }
  // }}}
  
  
  // private methods
  
  
  // static methods
  
  // {{{ getCountries
  /**
   * returns a hash of ISO 3166 identifiers/country names corresponding with the 
   * countries that are defined in SRA_ADDRESS_FORMAT_XML_DATA_FILE
   * @access public
   * @return  hash
   */
  function &getCountries() {
    static $_countries;
    
    if (!isset($_countries)) {
      $_countries = array();
      $resources =& SRA_ResourceBundle::getBundle(SRA_COUNTRY_PROPERTIES);
      if (!SRA_Error::isError($parser =& SRA_AddressFormat::_getXmlParser())) {
        $data =& $parser->getData(array('address-format'));
        $keys = array_keys($data);
        foreach($keys as $key) {
          $codes = explode(' ', $key);
          foreach($codes as $code) {
            $code = strtoupper($code);
            if (strlen($code) == 2 && $resources->getString($code) != $code) {
              $_countries[$code] = $resources->getString($code);
            }
          }
        }
        asort($_countries);
      }
      else {
        $_countries = $parser;
      }
    }
    return $_countries;
  }
  // }}}
    
	// {{{ getFieldOptions
	/**
	 * can be mapped as a global web service or invoked directly. will return the 
   * matching field options (a hash) based on the $params specified
   * @param array $params contains the following values:
   *   country: the iso 3166 code for the country
   *   field:   the id of the field
   *   locale:  the id of the locale for the address format
   *   value:   the current value of the tips field
   * @param int $limit the request limit
   * @param int $offset the request offset
   * @access public
   * @return array
	 */
	function &getFieldOptions($params, $limit=NULL, $offset=NULL) {
    if (isset($params['field']) && isset($params['country']) && SRA_AddressFormat::isValid($addressFormat = $params['locale'] ? SRA_AddressFormat::getInstanceWithLocale($params['country'], SRA_Locale::getLocale($params['locale'])) : SRA_AddressFormat::getInstance($params['country'])) && ($field =& $addressFormat->getField($params['field']))) {
      $options = $field['options'] ? $field['options'] : array();
      $keys = array_keys($options);
      if ($params['value']) {
        $lvalue = strtolower($params['value']);
        foreach($keys as $key) {
          if (strpos(strtolower($options[$key]), $lvalue) === FALSE && strtolower($key) != $lvalue) {
            unset($options[$key]);
          }
        }
      }
      if (isset($limit) || isset($offset)) { 
        $num = count($options);
        $options =& SRA_Util::applyLimitOffset($options, $limit, $offset, TRUE); 
        $options[SRA_WS_RESULT_COUNT_KEY] = $num;
      }
      return $options;
    }
    else {
      SRA_Error::logError($params, __FILE__, __LINE__);
      $msg = 'SRA_AddressFormat::getFieldOptions: Failed - $params above are not valid (country and field are required)';
      return SRA_Error::logError($msg, __FILE__, __LINE__);
    }
  }
	// }}}
  
	// {{{ getFieldValuesFromEntity
	/**
	 * returns the address field values from a sierra generated entity indexed by 
   * field id: (country|locality|postalCode|region|street)
   * @param object $entity the generated entity to retrieve the fields from. 
   * this entity must contain attributes whose names correspond with the field 
   * mappings defined in 'sierra/etc/l10n/address-field-mappings.properties'
   * @param string $view an optional view to check for in retrieving those 
   * values. if specified, and the $view is valid for a field attribute, the 
   * output of that view will be returned instead of the raw value
   * @param boolean $htmlLineBreaks whether or not to add html line breaks to 
   * the 'street' attribute when it is not rendered in a view
   * @access public
   * @return array
	 */
	function &getFieldValuesFromEntity(&$entity, $view=NULL, $htmlLineBreaks=TRUE) {
    $values = array();
    if (method_exists($entity, 'isAttribute')) {
      $fieldMappings =& SRA_ResourceBundle::getBundle(SRA_ADDRESS_FORMAT_FIELD_MAPPING_PROPERTIES);
      $fields = $fieldMappings->getKeys();
      foreach($fields as $field) {
        if ($entity->isAttribute($field)) {
          if ($view && $entity->hasView($view, $field)) {
            ob_start();
            $entity->renderAttribute($field, $view);
            $val = ob_get_contents();
            ob_end_clean();
          }
          else {
            $val = $entity->getAttribute($field);
            if ($htmlLineBreaks && $fieldMappings->getString($field) == 'street') { $val = str_replace("\n", '<br />', $val); }
          }
          $values[$fieldMappings->getString($field)] = $val;
        }
      }
    }
    $nl = NULL;
    return count($values) ? $values : $nl;
  }
	// }}}
  
  // {{{ getInstance
  /**
   * singleton method used to retrieve an instance of SRA_AddressFormat based 
   * on a country code. this method instantiates the address format using the 
   * locale provided through SRA_Controller::getUserLocale if available, 
   * SRA_Controller::getAppLocale otherwise
   * @param String $country the ISO 3166 country code. if not specified, 
   * SRA_COUNTRY_DEFAULT will be used
   * @access public
   * @return  SRA_AddressFormat
   */
  function getInstance($country=NULL) {
    $locale = SRA_Controller::getUserLocale() ? SRA_Controller::getUserLocale() : SRA_Controller::getAppLocale();
    return SRA_AddressFormat::getInstanceWithLocale($country, $locale);
  }
  // }}}
  
  // {{{ getInstanceWithLocale
  /**
   * singleton method used to retrieve an instance of SRA_AddressFormat based 
   * on a country code AND SRA_Locale
   * @param String $country the ISO 3166 country code. if not specified, 
   * SRA_COUNTRY_DEFAULT will be used
   * @param SRA_Locale $locale an explicit locale to use in instantiating the 
   * address format object
   * @access public
   * @return  SRA_AddressFormat
   */
  function getInstanceWithLocale($country=NULL, & $locale) {
    
    if (!SRA_Locale::isValid($locale)) {
      $msg = 'SRA_AddressFormat::getInstanceWithLocale: Failed - $locale parameter is not valid';
      return SRA_Error::logError($msg, __FILE__, __LINE__);
    }
    
    $countriesBundle =& SRA_ResourceBundle::getBundle(SRA_ADDRESS_FORMAT_COUNTRY_PROPERTIES, $locale);
    $country = $country ? $country : $locale->getCountry();
    if (!$countriesBundle->getString($country)) { $country = SRA_COUNTRY_DEFAULT; }
    
    if (!SRA_Error::isError($parser =& SRA_AddressFormat::_getXmlParser())) {
      static $_addressFormatInstances = array();
      
      $id = $country . '-' . $locale->getId();
      if (!isset($_addressFormatInstances[$id])) {
        // initialize singleton static reference
        $country = strtolower($country);
        $data =& $parser->getData(array('address-format'));
        $keys = array_keys($data);
        foreach($keys as $key) {
          if (strpos($key, $country) !== FALSE) {
            $_addressFormatInstances[$id] = new SRA_AddressFormat(strtoupper($country), $data[$key], $locale);
            break;
          }
        }
      }
      return $_addressFormatInstances[$id];
    }
    else {
      return $parser;
    }
  }
  // }}}
  
  // {{{ isFieldLabel
  /**
   * returns true if $value is a label for $attr
   * @param string $attr the address attribute (country|locality|postalCode|region|street)
   * @param string $value the value for that attribute
   * @access public
   * @return boolean
   */
  function isFieldLabel($attr, $value) {
    $value = strtolower(trim($value));
    $fields =& SRA_ResourceBundle::getBundle(SRA_ADDRESS_FORMAT_FIELD_PROPERTIES);
    $fieldMappings =& SRA_ResourceBundle::getBundle(SRA_ADDRESS_FORMAT_FIELD_MAPPING_PROPERTIES);
    $mappings =& $fieldMappings->getData();
    foreach($mappings as $key => $id) {
      if ($attr == $id && ($value == $attr || $value == $id || $value == strtolower(trim($fields->getString($key))))) { return TRUE; }
    }
    return FALSE;
  }
  // }}}
  
  // {{{ isValid
  /**
   * Static method that returns true if the object parameter is an 
   * SRA_AddressFormat object
   * @param Object $object the object to validate
   * @access public
   * @return boolean
   */
  function isValid($object) {
    return (is_object($object) && (!isset($object->err) || !SRA_Error::isError($object->err)) && strtolower(get_class($object)) == 'sra_addressformat');
  }
  // }}}
  
  // {{{ _getXmlParser
  /**
   * returns a reference to the xml parser for SRA_ADDRESS_FORMAT_XML_DATA_FILE
   * @access private
   * @return  SRA_XmlParser
   */
  function &_getXmlParser() {
    static $_addressFormatData;
    
    // initialize the xml parser
    if (!isset($_addressFormatData)) {
      if (!SRA_XmlParser::isValid($_addressFormatData =& SRA_XmlParser::getXmlParser(SRA_ADDRESS_FORMAT_XML_DATA_FILE))) {
        $msg = 'SRA_AddressFormat::_getXmlParser: Failed - XML definition file \'' . SRA_ADDRESS_FORMAT_XML_DATA_FILE . '\' could not be parsed';
        return SRA_Error::logError($msg, __FILE__, __LINE__);
      }
    }
    
    return $_addressFormatData;
  }
  // }}}

}
// }}}

// assign a reference to this object to the template
if ($tpl =& SRA_Controller::getAppTemplate()) {
  $tpl->assignByRef('SRA_AddressFormat', SRA_AddressFormat::getInstance());
}
?>
Return current item: Sierra-php PHP Application Framework