model.rb 4.04 KB
class Kalibro::Model

  attr_accessor :errors

  def initialize(attributes={})
    attributes.each { |field, value| send("#{field}=", value) if self.class.is_valid?(field) }
    @errors = []
  end


  def to_hash(options={})
    hash = Hash.new
    excepts = options[:except].nil? ? [] : options[:except]
    excepts << :errors
    fields.each do |field|
      if(!excepts.include?(field))
        field_value = send(field)
        if !field_value.nil?
            hash[field] = convert_to_hash(field_value)
          if field_value.is_a?(Kalibro::Model)
            hash = {:attributes! => {}}.merge(hash)
            hash[:attributes!][field.to_sym] = {
              'xmlns:xsi'=> 'http://www.w3.org/2001/XMLSchema-instance',
              'xsi:type' => 'kalibro:' + xml_instance_class_name(field_value)  }
          end
        end
      end
    end
    hash
  end

  def self.request(action, request_body = nil)
    response = client(endpoint).request(:kalibro, action) { soap.body = request_body }
    response.to_hash["#{action}_response".to_sym] # response is a Savon::SOAP::Response, and to_hash is a Savon::SOAP::Response method
  end

  def self.to_objects_array value
    array = value.kind_of?(Array) ? value : [value]
    array.each.collect { |element| to_object(element) }
  end

  def self.to_object value
    value.kind_of?(Hash) ? new(value) : value
  end

  def self.create(attributes={})
    new_model = new attributes
    new_model.save
    new_model
  end

  def self.find(id)
    if(exists?(id))
      new request(find_action, id_params(id))["#{class_name.underscore}".to_sym]
    else
      raise Kalibro::Errors::RecordNotFound
    end
  end

  def save
    begin
      self.id = self.class.request(save_action, save_params)["#{instance_class_name.underscore}_id".to_sym]
	    true
	  rescue Exception => exception
	    add_error exception
	    false
	  end
  end

  def destroy
    begin
      self.class.request(destroy_action, destroy_params)
    rescue Exception => exception
	    add_error exception
    end
  end

  def self.exists?(id)
    request(exists_action, id_params(id))[:exists]
  end

  protected

  def fields
    instance_variable_names.each.collect { |variable| variable.to_s.sub(/@/, '').to_sym }
  end

  def convert_to_hash(value)
    return value if value.nil?
    return value.collect { |element| convert_to_hash(element) } if value.is_a?(Array)
    return value.to_hash if value.is_a?(Kalibro::Model)
    return self.class.date_with_milliseconds(value) if value.is_a?(DateTime)
    return 'INF' if value.is_a?(Float) and value.infinite? == 1
    return '-INF' if value.is_a?(Float) and value.infinite? == -1
    value.to_s
  end

  def xml_instance_class_name(object)
    xml_name = object.class.name
    xml_name["Kalibro::"] = ""
    xml_name[0..0] = xml_name[0..0].downcase
    xml_name + "Xml"
  end

  def self.client(endpoint)
    service_address = YAML.load_file("#{RAILS_ROOT}/plugins/mezuro/service.yml")
    Savon::Client.new("#{service_address}#{endpoint}Endpoint/?wsdl")
  end

  def self.is_valid?(field)
    field.to_s[0] != '@' and field != :attributes! and (field.to_s =~ /xsi/).nil?
  end

  def self.date_with_milliseconds(date)
    milliseconds = "." + (date.sec_fraction * 60 * 60 * 24 * 1000).to_s
    date.to_s[0..18] + milliseconds + date.to_s[19..-1]
  end

  def instance_class_name
    self.class.name.gsub(/Kalibro::/,"")
  end

  def self.endpoint
    class_name
  end

  def save_action
    "save_#{instance_class_name.underscore}".to_sym
  end

  def save_params
    {instance_class_name.underscore.to_sym => self.to_hash}
  end

  def destroy_action
    "delete_#{instance_class_name.underscore}".to_sym
  end

  def destroy_params
    {"#{instance_class_name.underscore}_id".to_sym => self.id}
  end

  def self.class_name
    self.name.gsub(/Kalibro::/,"")
  end

  def self.exists_action
    "#{class_name.underscore}_exists".to_sym
  end

  def self.id_params(id)
    {"#{class_name.underscore}_id".to_sym => id}
  end

  def self.find_action
    "get_#{class_name.underscore}".to_sym
  end

  def add_error(exception)
    @errors << exception
  end

end