Class: Bronto::Base

Inherits:
Object show all
Defined in:
lib/bronto/base.rb

Direct Known Subclasses

Contact, Delivery, Field, List, Message, MessageFolder

Constant Summary collapse

@@api_key =
nil

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Base

Accepts a hash whose keys should be setters on the object.



166
167
168
169
170
# File 'lib/bronto/base.rb', line 166

def initialize(options = {})
  self.api_key = self.class.api_key
  self.errors = Errors.new
  options.each { |k,v| send("#{k}=", v) if respond_to?("#{k}=") }
end

Instance Attribute Details

#api_keyObject

Returns the value of attribute api_key.



10
11
12
# File 'lib/bronto/base.rb', line 10

def api_key
  @api_key
end

#errorsObject

Returns the value of attribute errors.



10
11
12
# File 'lib/bronto/base.rb', line 10

def errors
  @errors
end

#idObject

Returns the value of attribute id.



10
11
12
# File 'lib/bronto/base.rb', line 10

def id
  @id
end

Class Method Details

.api(api_key, refresh = false) ⇒ Object

Sets up the Savon SOAP client object, including sessionHeaders and returns the client.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/bronto/base.rb', line 50

def self.api(api_key, refresh = false)
  return connection_cache[api_key][:client] unless refresh || session_expired(api_key) || connection_cache[api_key].nil?

  client = Savon.client(wsdl: 'https://api.bronto.com/v4?wsdl', ssl_version: :TLSv1_2)
  resp = client.call(:login, message: { api_token: api_key })

  connection_cache[api_key] = {
    client: Savon.client(
      wsdl: 'https://api.bronto.com/v4?wsdl',
      soap_header: {
        "tns:sessionHeader" => { session_id: resp.body[:login_response][:return] }
      },
      read_timeout: 600 # Give Bronto up to 10 minutes to reply
    ),
    last_used: nil
  }
  connection_cache[api_key][:client]
end

.api_keyObject



19
20
21
# File 'lib/bronto/base.rb', line 19

def self.api_key
  @@api_key
end

.api_key=(api_key) ⇒ Object

Getter/Setter for global API Key.



15
16
17
# File 'lib/bronto/base.rb', line 15

def self.api_key=(api_key)
  @@api_key = api_key
end

.connection_cacheObject



23
24
25
# File 'lib/bronto/base.rb', line 23

def self.connection_cache
  @@connection_cache ||= {}
end

.create(*objs) ⇒ Object

Tells the remote server to create the passed in collection of Bronto::Base objects. The object should implement ‘to_hash` to return a hash in the format expected by the SOAP API.

Returns the same collection of objects that was passed in. Objects whose creation succeeded will be assigned the ID returned from Bronto. The first element passed in can be a string containing the API key; if none passed, will fall back to the global key.



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/bronto/base.rb', line 110

def self.create(*objs)
  objs = objs.flatten
  api_key = objs.first.is_a?(String) ? objs.shift : self.api_key

  resp = request(:add, {plural_class_name => objs.map(&:to_hash)})

  objs.each { |o| o.errors.clear }

  Array.wrap(resp[:return][:results]).each_with_index do |result, i|
    if result[:is_error]
      objs[i].errors.add(result[:error_code], result[:error_string])
    else
      objs[i].id = result[:id]
    end
  end

  objs
end

.destroy(*objs) ⇒ Object

Destroys a collection of Bronto::Base objects on the remote server.

Returns the same collection of objects that was passed in. Objects whose destruction succeeded will have a nil ID.

The first element passed in can be a string containing the API key; if none passed, will fall back to the global key.



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/bronto/base.rb', line 148

def self.destroy(*objs)
  objs = objs.flatten
  api_key = objs.first.is_a?(String) ? objs.shift : self.api_key

  resp = request(:delete, {plural_class_name => objs.map { |o| { id: o.id }}})

  Array.wrap(resp[:return][:results]).each_with_index do |result, i|
    if result[:is_error]
      objs[i].errors.add(result[:error_code], result[:error_string])
    else
      objs[i].id = nil
    end
  end

  objs
end

.find(filter = Bronto::Filter.new, page_number = 1, api_key = nil) ⇒ Object

Finds objects matching the ‘filter` (a Bronto::Filter instance).



96
97
98
99
100
101
102
# File 'lib/bronto/base.rb', line 96

def self.find(filter = Bronto::Filter.new, page_number = 1, api_key = nil)
  api_key = api_key || self.api_key

  resp = request(:read, { filter: filter.to_hash, page_number: page_number })

  Array.wrap(resp[:return]).map { |hash| new(hash) }
end

.plural_class_nameObject

Simple helper method to convert class name to downcased pluralized version (e.g., Field -> fields).



28
29
30
# File 'lib/bronto/base.rb', line 28

def self.plural_class_name
  self.to_s.split("::").last.downcase.pluralize
end

.request(method, message = {}) ⇒ Object

The primary method used to interface with the SOAP API.

If a symbol is passed in, it is converted to “method_plural_class_name” (e.g., :read => read_lists). A string method is used as-is. The message is a hash and becomes the body of the SOAP request



37
38
39
40
41
42
43
44
45
46
47
# File 'lib/bronto/base.rb', line 37

def self.request(method, message = {})
  api_key = api_key || self.api_key

  method = "#{method}_#{plural_class_name}" if method.is_a? Symbol

  resp = api(api_key).call(method.to_sym, message: message)

  connection_cache[api_key][:last_used] = Time.now

  resp.body["#{method}_response".to_sym]
end

.save(*objs) ⇒ Object

Saves a collection of Bronto::Base objects. Objects without IDs are considered new and are ‘create`d; objects with IDs are considered existing and are `update`d.



81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/bronto/base.rb', line 81

def self.save(*objs)
  objs = objs.flatten
  api_key = objs.first.is_a?(String) ? objs.shift : self.api_key

  updates = []
  creates = []

  objs.each { |o| (o.id.present? ? updates : creates) << o }

  update(updates) if updates.count > 0
  create(creates) if creates.count > 0
  objs
end

.session_expired(api_key) ⇒ Object

returns true if a cached session identifier is missing or is too old



70
71
72
73
74
75
76
77
# File 'lib/bronto/base.rb', line 70

def self.session_expired(api_key)
  return true if (connection_cache[api_key].nil?)
  last_used = connection_cache[api_key][:last_used]
  return true if (last_used == nil)
  return true if (Time.now.tv_sec - last_used.tv_sec > SESSION_REUSE_SECONDS)

  false
end

.update(*objs) ⇒ Object

Updates a collection of Bronto::Base objects. The objects should exist on the remote server. The object should implement ‘to_hash` to return a hash in the format expected by the SOAP API. The first element passed in can be a string containing the API key; if none passed, will fall back to the global key.



132
133
134
135
136
137
138
139
140
# File 'lib/bronto/base.rb', line 132

def self.update(*objs)
  objs = objs.flatten
  api_key = objs.first.is_a?(String) ? objs.shift : self.api_key

  resp = request(:update, {plural_class_name => objs.map(&:to_hash)})

  objs.each { |o| o.errors.clear }
  objs
end

Instance Method Details

#createObject

Creates the object. See ‘Bronto::Base.create` for more info.



203
204
205
206
# File 'lib/bronto/base.rb', line 203

def create
  res = self.class.create(self.api_key, self)
  res.first
end

#destroyObject

Destroys the object. See ‘Bronto::Base.destroy` for more info.



214
215
216
# File 'lib/bronto/base.rb', line 214

def destroy
  self.class.destroy(self.api_key, self).first
end

#reloadObject



182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/bronto/base.rb', line 182

def reload
  return if self.id.blank?

  # The block below is evaluated in a weird scope so we need to capture self as _self for use inside the block.
  _self = self

  resp = request(:read, { filter: { id: _self.id } })

  resp[:return].each do |k, v|
    self.send("#{k}=", v) if self.respond_to? "#{k}="
  end

  nil
end

#request(method, message = {}) ⇒ Object

Convenience instance method that calls the class ‘request` method.



178
179
180
# File 'lib/bronto/base.rb', line 178

def request(method, message = {})
  self.class.request(method, message)
end

#saveObject

Saves the object. If the object has an ID, it is updated. Otherwise, it is created.



198
199
200
# File 'lib/bronto/base.rb', line 198

def save
  id.blank? ? create : update
end

#to_hashObject

‘to_hash` should be overridden to provide a hash whose structure matches the structure expected by the API.



173
174
175
# File 'lib/bronto/base.rb', line 173

def to_hash
  {}
end

#updateObject

Updates the object. See ‘Bronto::Base.update` for more info.



209
210
211
# File 'lib/bronto/base.rb', line 209

def update
  self.class.update(self.api_key, self).first
end