Bronto_Extension - Version 2.0.0

Version Notes

This is the first release of a new Bronto extension that replaces and deprecates the "Bronto Order Import for Magento," "Bronto Shopping Cart Abandonment," and "Bronto Newsletter Opt-In" extensions. All of the functionality of those extensions is included in this Bronto Extension for Magento.

For installation and configuration instructions, as well as a full list of new features and known issues, please review the Implementation Guide at http://a.bron.to/magento.

Download this release

Release Info

Developer Chris Geiss
Extension Bronto_Extension
Version 2.0.0
Comparing to
See all releases


Version 2.0.0

Files changed (79) hide show
  1. app/design/frontend/base/default/layout/bronto/newsletter.xml +12 -0
  2. app/design/frontend/base/default/template/bronto/newsletter/js.phtml +56 -0
  3. app/etc/modules/Bronto_All.xml +15 -0
  4. app/etc/modules/Bronto_ConflictChecker.xml +9 -0
  5. app/etc/modules/Bronto_Customer.xml +12 -0
  6. app/etc/modules/Bronto_Email.xml +12 -0
  7. app/etc/modules/Bronto_Newsletter.xml +13 -0
  8. app/etc/modules/Bronto_Order.xml +12 -0
  9. app/etc/modules/Bronto_PermissionChecker.xml +9 -0
  10. app/etc/modules/Bronto_Reminder.xml +14 -0
  11. app/etc/modules/Bronto_Roundtrip.xml +12 -0
  12. lib/Bronto/Api.php +608 -0
  13. lib/Bronto/Api/Account.php +55 -0
  14. lib/Bronto/Api/Account/Exception.php +10 -0
  15. lib/Bronto/Api/Account/Row.php +21 -0
  16. lib/Bronto/Api/Activity.php +213 -0
  17. lib/Bronto/Api/Activity/Exception.php +9 -0
  18. lib/Bronto/Api/Activity/Row.php +136 -0
  19. lib/Bronto/Api/ApiToken.php +126 -0
  20. lib/Bronto/Api/ApiToken/Exception.php +6 -0
  21. lib/Bronto/Api/ApiToken/Row.php +80 -0
  22. lib/Bronto/Api/Contact.php +104 -0
  23. lib/Bronto/Api/Contact/Exception.php +20 -0
  24. lib/Bronto/Api/Contact/Row.php +396 -0
  25. lib/Bronto/Api/Conversion.php +43 -0
  26. lib/Bronto/Api/Conversion/Exception.php +8 -0
  27. lib/Bronto/Api/Conversion/Row.php +102 -0
  28. lib/Bronto/Api/Delivery.php +83 -0
  29. lib/Bronto/Api/Delivery/Exception.php +20 -0
  30. lib/Bronto/Api/Delivery/Recipient.php +19 -0
  31. lib/Bronto/Api/Delivery/Row.php +235 -0
  32. lib/Bronto/Api/DeliveryGroup.php +97 -0
  33. lib/Bronto/Api/DeliveryGroup/Exception.php +18 -0
  34. lib/Bronto/Api/DeliveryGroup/Row.php +55 -0
  35. lib/Bronto/Api/Exception.php +247 -0
  36. lib/Bronto/Api/Field.php +133 -0
  37. lib/Bronto/Api/Field/Exception.php +14 -0
  38. lib/Bronto/Api/Field/Predefined.php +303 -0
  39. lib/Bronto/Api/Field/Row.php +59 -0
  40. lib/Bronto/Api/Field/TypeGuesser.php +126 -0
  41. lib/Bronto/Api/List.php +54 -0
  42. lib/Bronto/Api/List/Exception.php +15 -0
  43. lib/Bronto/Api/List/Row.php +124 -0
  44. lib/Bronto/Api/Login.php +43 -0
  45. lib/Bronto/Api/Login/ContactInformation.php +90 -0
  46. lib/Bronto/Api/Login/Exception.php +6 -0
  47. lib/Bronto/Api/Login/Row.php +36 -0
  48. lib/Bronto/Api/Message.php +35 -0
  49. lib/Bronto/Api/Message/Exception.php +20 -0
  50. lib/Bronto/Api/Message/Row.php +80 -0
  51. lib/Bronto/Api/MessageRule.php +40 -0
  52. lib/Bronto/Api/MessageRule/Exception.php +10 -0
  53. lib/Bronto/Api/MessageRule/Row.php +56 -0
  54. lib/Bronto/Api/Object.php +580 -0
  55. lib/Bronto/Api/Order.php +18 -0
  56. lib/Bronto/Api/Order/Exception.php +6 -0
  57. lib/Bronto/Api/Order/Product.php +65 -0
  58. lib/Bronto/Api/Order/Row.php +82 -0
  59. lib/Bronto/Api/Row.php +730 -0
  60. lib/Bronto/Api/Row/Exception.php +6 -0
  61. lib/Bronto/Api/Rowset.php +395 -0
  62. lib/Bronto/Api/Rowset/Exception.php +6 -0
  63. lib/Bronto/Api/Rowset/Iterator.php +403 -0
  64. lib/Bronto/Api/Segment.php +36 -0
  65. lib/Bronto/Api/Segment/Exception.php +6 -0
  66. lib/Bronto/Api/Segment/Row.php +67 -0
  67. lib/Bronto/SoapClient.php +18 -0
  68. lib/Bronto/Util/Colors.php +193 -0
  69. lib/Bronto/Util/CountryCodes.php +257 -0
  70. lib/Bronto/Util/Retryer/FileRetryer.php +123 -0
  71. lib/Bronto/Util/Retryer/RetryerException.php +6 -0
  72. lib/Bronto/Util/Retryer/RetryerInterface.php +17 -0
  73. lib/Bronto/Util/Uuid.php +75 -0
  74. package.xml +51 -0
  75. skin/adminhtml/base/default/bronto/cron.css +97 -0
  76. skin/adminhtml/base/default/bronto/images/bg_notifications.gif +0 -0
  77. skin/adminhtml/base/default/bronto/images/logo.jpg +0 -0
  78. skin/adminhtml/base/default/bronto/images/message_approved.gif +0 -0
  79. skin/adminhtml/base/default/bronto/images/message_not_approved.gif +0 -0
app/design/frontend/base/default/layout/bronto/newsletter.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout version="0.1.0">
3
+ <checkout_onepage_index>
4
+ <reference name="content">
5
+ <block type="bronto_newsletter/checkout_onepage_newsletter" name="checkout.onepage.billing.newsletter.js" after="-">
6
+ <action method="setTemplate" ifconfig="bronto_newsletter/settings/enabled">
7
+ <template>bronto/newsletter/js.phtml</template>
8
+ </action>
9
+ </block>
10
+ </reference>
11
+ </checkout_onepage_index>
12
+ </layout>
app/design/frontend/base/default/template/bronto/newsletter/js.phtml ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @var $this Bronto_Newsletter_Block_Checkout_Onepage_Newsletter
4
+ */
5
+ ?>
6
+
7
+ <?php if ($this->isEnabled()): ?>
8
+
9
+ <script>
10
+ function prepareNewsletterField() {
11
+ Element.show('register-customer-newsletter');
12
+ if (typeof(checkout) != 'undefined') {
13
+ if (checkout.method == 'register') {
14
+ <?php if ($this->isEnabledForRegisterCheckout()): ?>
15
+ Element.show('register-customer-newsletter');
16
+ <?php if ($this->isSubscribed() || $this->isEnabledCheckedByDefault()): ?>
17
+ $('billing:is_subscribed_box').checked = true;
18
+ $('billing:is_subscribed').value = 1;
19
+ <?php endif ?>
20
+ <?php else: ?>
21
+ Element.hide('register-customer-newsletter');
22
+ $('billing:is_subscribed_box').checked = false;
23
+ $('billing:is_subscribed').value = 0;
24
+ <?php endif ?>
25
+ } else if (checkout.method == 'guest') {
26
+ <?php if ($this->isEnabledForGuestCheckout()): ?>
27
+ Element.show('register-customer-newsletter');
28
+ <?php if ($this->isSubscribed() || $this->isEnabledCheckedByDefault()): ?>
29
+ $('billing:is_subscribed_box').checked = true;
30
+ $('billing:is_subscribed').value = 1;
31
+ <?php endif ?>
32
+ <?php else: ?>
33
+ Element.hide('register-customer-newsletter');
34
+ $('billing:is_subscribed_box').checked = false;
35
+ $('billing:is_subscribed').value = 0;
36
+ <?php endif ?>
37
+ }
38
+ }
39
+ <?php if ($this->isSubscribed() && !$this->isEnabledIfAlreadySubscribed()): ?>
40
+ Element.hide('register-customer-newsletter');
41
+ <?php endif; ?>
42
+ }
43
+
44
+ Event.observe(window, 'load', function() {
45
+ if ($('onepage-guest-register-button') != null) {
46
+ Event.observe('onepage-guest-register-button', 'click', function() {
47
+ prepareNewsletterField();
48
+ });
49
+ }
50
+ $$('#co-billing-form fieldset')[0].insert('<style>.col1-layout .billing_is_subscribed_box { margin-left: 240px !important; } .col1-layout #billing_subscribed_label { text-align: left; }</style>');
51
+ $$('#co-billing-form fieldset')[0].insert('<input id="billing:is_subscribed" type="hidden" name="billing[is_subscribed]" value="1" /><input id="billing:is_subscribed_box" class="billing_is_subscribed_box" type="checkbox" onchange="$(\'billing:is_subscribed\').value = this.checked ? 1 : 0" checked="checked" title="<?php echo $this->__($this->getCheckboxLabelText()) ?>" style="float:left; width: auto; margin: 2px 8px 0 0;" /><label id="billing_subscribed_label" for="billing[is_subscribed]"><?php echo $this->__($this->getCheckboxLabelText()) ?></label>');
52
+ prepareNewsletterField();
53
+ });
54
+ </script>
55
+
56
+ <?php endif ?>
app/etc/modules/Bronto_All.xml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Bronto_Common>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ <depends>
8
+ <Mage_Adminhtml/>
9
+ <Mage_Customer/>
10
+ <Mage_Checkout/>
11
+ <Mage_Sales/>
12
+ </depends>
13
+ </Bronto_Common>
14
+ </modules>
15
+ </config>
app/etc/modules/Bronto_ConflictChecker.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Bronto_ConflictChecker>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ </Bronto_ConflictChecker>
8
+ </modules>
9
+ </config>
app/etc/modules/Bronto_Customer.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Bronto_Customer>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ <depends>
8
+ <Bronto_Common/>
9
+ </depends>
10
+ </Bronto_Customer>
11
+ </modules>
12
+ </config>
app/etc/modules/Bronto_Email.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Bronto_Email>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ <depends>
8
+ <Bronto_Common/>
9
+ </depends>
10
+ </Bronto_Email>
11
+ </modules>
12
+ </config>
app/etc/modules/Bronto_Newsletter.xml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Bronto_Newsletter>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ <depends>
8
+ <Bronto_Common/>
9
+ <Mage_Newsletter/>
10
+ </depends>
11
+ </Bronto_Newsletter>
12
+ </modules>
13
+ </config>
app/etc/modules/Bronto_Order.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Bronto_Order>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ <depends>
8
+ <Bronto_Common/>
9
+ </depends>
10
+ </Bronto_Order>
11
+ </modules>
12
+ </config>
app/etc/modules/Bronto_PermissionChecker.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Bronto_PermissionChecker>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ </Bronto_PermissionChecker>
8
+ </modules>
9
+ </config>
app/etc/modules/Bronto_Reminder.xml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Bronto_Reminder>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ <depends>
8
+ <Bronto_Common/>
9
+ <Mage_Wishlist/>
10
+ <Mage_SalesRule/>
11
+ </depends>
12
+ </Bronto_Reminder>
13
+ </modules>
14
+ </config>
app/etc/modules/Bronto_Roundtrip.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Bronto_Roundtrip>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ <depends>
8
+ <Bronto_Common/>
9
+ </depends>
10
+ </Bronto_Roundtrip>
11
+ </modules>
12
+ </config>
lib/Bronto/Api.php ADDED
@@ -0,0 +1,608 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ */
6
+ class Bronto_Api
7
+ {
8
+ /** URI */
9
+ const BASE_WSDL = 'https://api.bronto.com/v4?wsdl';
10
+ const BASE_LOCATION = 'https://api.bronto.com/v4';
11
+ const BASE_URL = 'http://api.bronto.com/v4';
12
+
13
+ /**
14
+ * @var SoapClient
15
+ */
16
+ protected $_soapClient;
17
+
18
+ /**
19
+ * API token
20
+ *
21
+ * @var string
22
+ */
23
+ protected $_token;
24
+
25
+ /**
26
+ * @var array
27
+ */
28
+ protected $_options = array(
29
+ // Bronto
30
+ 'soap_client' => 'Bronto_SoapClient',
31
+ 'refresh_on_save' => false,
32
+ 'retry_limit' => 5,
33
+ 'debug' => false,
34
+ 'retryer' => array(
35
+ 'type' => null,
36
+ 'path' => null,
37
+ ),
38
+ // SoapClient
39
+ 'soap_version' => SOAP_1_1,
40
+ 'compression' => true,
41
+ 'encoding' => 'UTF-8',
42
+ 'trace' => false,
43
+ 'exceptions' => true,
44
+ 'cache_wsdl' => WSDL_CACHE_BOTH,
45
+ 'user_agent' => 'Bronto_Api <https://github.com/leek/bronto_service>',
46
+ 'features' => SOAP_SINGLE_ELEMENT_ARRAYS,
47
+ 'connection_timeout' => 30,
48
+ );
49
+
50
+ /**
51
+ * Cache of class objects
52
+ *
53
+ * @var array
54
+ */
55
+ protected $_classCache = array();
56
+
57
+ /**
58
+ * @var bool
59
+ */
60
+ protected $_connected = false;
61
+
62
+ /**
63
+ * @var bool
64
+ */
65
+ protected $_authenticated = false;
66
+
67
+ /**
68
+ * @var Bronto_Util_Retryer_RetryerInterface
69
+ */
70
+ protected $_retryer;
71
+
72
+ /**
73
+ * @var Bronto_Util_Uuid
74
+ */
75
+ protected $_uuid;
76
+
77
+ /**
78
+ * @param string $token
79
+ * @param array $options
80
+ */
81
+ public function __construct($token = null, array $options = array())
82
+ {
83
+ if (!extension_loaded('soap')) {
84
+ throw new Bronto_Api_Exception('SOAP extension is not loaded.');
85
+ }
86
+
87
+ if (!extension_loaded('openssl')) {
88
+ throw new Bronto_Api_Exception('OpenSSL extension is not loaded.');
89
+ }
90
+
91
+ $this->_options['compression'] = SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP;
92
+ $this->_setOptions($options);
93
+
94
+ if ($token !== null) {
95
+ $this->setToken($token);
96
+ }
97
+
98
+ ini_set('default_socket_timeout', 120);
99
+ }
100
+
101
+ /**
102
+ * Login with API token
103
+ *
104
+ * @return Bronto_Api
105
+ */
106
+ public function login()
107
+ {
108
+ $token = $this->getToken();
109
+ if (empty($token)) {
110
+ throw new Bronto_Api_Exception('Token is empty or invalid.', Bronto_Api_Exception::NO_TOKEN);
111
+ }
112
+
113
+ try {
114
+ // Get a new SoapClient
115
+ $this->reset();
116
+ $client = $this->getSoapClient(false);
117
+ $sessionId = $client->login(array('apiToken' => $token))->return;
118
+ $client->__setSoapHeaders(array(
119
+ new SoapHeader(self::BASE_URL, 'sessionHeader', array('sessionId' => $sessionId))
120
+ ));
121
+ $this->_authenticated = true;
122
+ } catch (Exception $e) {
123
+ $this->throwException($e);
124
+ }
125
+
126
+ return $this;
127
+ }
128
+
129
+ /**
130
+ * We want all Exceptions to be Bronto_Api_Exception for request/response
131
+ *
132
+ * @param string|Exception $exception
133
+ * @param string $message
134
+ * @param string $code
135
+ * @return Bronto_Api_Exception
136
+ */
137
+ public function throwException($exception, $message = null, $code = null)
138
+ {
139
+ if ($exception instanceOf Exception) {
140
+ if ($exception instanceOf Bronto_Api_Exception) {
141
+ // Good
142
+ } else {
143
+ // Convert
144
+ $exception = new Bronto_Api_Exception($exception->getMessage(), $exception->getCode(), null, $exception);
145
+ }
146
+ } else {
147
+ if (is_string($exception)) {
148
+ if (class_exists($exception, false)) {
149
+ $exception = new $exception($message, $code);
150
+ } else {
151
+ $exception = new Bronto_Api_Exception($exception);
152
+ }
153
+ }
154
+ }
155
+
156
+ // For tracking request/response in debug mode
157
+ if ($this->getDebug()) {
158
+ /* @var $exception Bronto_Api_Exception */
159
+ $exception->setRequest($this->getLastRequest());
160
+ $exception->setResponse($this->getLastResponse());
161
+ }
162
+
163
+ throw $exception;
164
+ }
165
+
166
+ /**
167
+ * Set API token
168
+ *
169
+ * @param string $token
170
+ * @return Bronto_Api
171
+ */
172
+ public function setToken($token)
173
+ {
174
+ $this->reset();
175
+ $this->_token = $token;
176
+ return $this;
177
+ }
178
+
179
+ /**
180
+ * Get token
181
+ *
182
+ * @return string
183
+ */
184
+ public function getToken()
185
+ {
186
+ return $this->_token;
187
+ }
188
+
189
+ /**
190
+ * @return Bronto_Api_ApiToken_Row
191
+ */
192
+ public function getTokenInfo()
193
+ {
194
+ $apiToken = $this->getApiTokenObject()->createRow();
195
+ $apiToken->id = $this->getToken();
196
+ $apiToken->read();
197
+
198
+ return $apiToken;
199
+ }
200
+
201
+ /**
202
+ * @param array $options
203
+ * @return Bronto_Api
204
+ */
205
+ protected function _setOptions(array $options = array())
206
+ {
207
+ foreach ($options as $name => $value) {
208
+ $this->_setOption($name, $value);
209
+ }
210
+ return $this;
211
+ }
212
+
213
+ /**
214
+ * @param string $name
215
+ * @param mixed $value
216
+ * @return Bronto_Api
217
+ */
218
+ protected function _setOption($name, $value)
219
+ {
220
+ if (isset($this->_options[$name])) {
221
+ // Some settings need checked
222
+ switch ($name) {
223
+ case 'soap_client':
224
+ if (!class_exists($value)) {
225
+ $this->throwException("Unable to load class: {$value} as SoapClient.");
226
+ }
227
+ break;
228
+ case 'soap_version':
229
+ if (!in_array($value, array(SOAP_1_1, SOAP_1_2))) {
230
+ $this->throwException('Invalid soap_version value specified. Use SOAP_1_1 or SOAP_1_2 constants.');
231
+ }
232
+ break;
233
+ case 'cache_wsdl':
234
+ if (!in_array($value, array(WSDL_CACHE_NONE, WSDL_CACHE_DISK, WSDL_CACHE_MEMORY, WSDL_CACHE_BOTH))) {
235
+ $this->throwException('Invalid cache_wsdl value specified.');
236
+ }
237
+ // If debug mode, ignore WSDL cache setting
238
+ if ($this->getDebug()) {
239
+ $value = WSDL_CACHE_NONE;
240
+ }
241
+ break;
242
+ case 'debug':
243
+ if ($value == true) {
244
+ $this->_options['trace'] = true;
245
+ $this->_options['cache_wsdl'] = WSDL_CACHE_NONE;
246
+ }
247
+ break;
248
+ }
249
+
250
+ $this->_options[$name] = $value;
251
+ }
252
+ return $this;
253
+ }
254
+
255
+ /**
256
+ * @param string $name
257
+ * @param mixed $default
258
+ * @return mixed
259
+ */
260
+ public function getOption($name, $default = null)
261
+ {
262
+ if (isset($this->_options[$name])) {
263
+ return $this->_options[$name];
264
+ }
265
+ return $default;
266
+ }
267
+
268
+ /**
269
+ * Proxy for intellisense
270
+ *
271
+ * @return Bronto_Api_Account
272
+ */
273
+ public function getAccountObject()
274
+ {
275
+ return $this->getObject('account');
276
+ }
277
+
278
+ /**
279
+ * Proxy for intellisense
280
+ *
281
+ * @return Bronto_Api_Activity
282
+ */
283
+ public function getActivityObject()
284
+ {
285
+ return $this->getObject('activity');
286
+ }
287
+
288
+ /**
289
+ * Proxy for intellisense
290
+ *
291
+ * @return Bronto_Api_ApiToken
292
+ */
293
+ public function getApiTokenObject()
294
+ {
295
+ return $this->getObject('apiToken');
296
+ }
297
+
298
+ /**
299
+ * Proxy for intellisense
300
+ *
301
+ * @return Bronto_Api_Contact
302
+ */
303
+ public function getContactObject()
304
+ {
305
+ return $this->getObject('contact');
306
+ }
307
+
308
+ /**
309
+ * Proxy for intellisense
310
+ *
311
+ * @return Bronto_Api_Conversion
312
+ */
313
+ public function getConversionObject()
314
+ {
315
+ return $this->getObject('conversion');
316
+ }
317
+
318
+ /**
319
+ * Proxy for intellisense
320
+ *
321
+ * @return Bronto_Api_Delivery
322
+ */
323
+ public function getDeliveryObject()
324
+ {
325
+ return $this->getObject('delivery');
326
+ }
327
+
328
+ /**
329
+ * Proxy for intellisense
330
+ *
331
+ * @return Bronto_Api_DeliveryGroup
332
+ */
333
+ public function getDeliveryGroupObject()
334
+ {
335
+ return $this->getObject('deliveryGroup');
336
+ }
337
+
338
+ /**
339
+ * Proxy for intellisense
340
+ *
341
+ * @return Bronto_Api_Field
342
+ */
343
+ public function getFieldObject()
344
+ {
345
+ return $this->getObject('field');
346
+ }
347
+
348
+ /**
349
+ * Proxy for intellisense
350
+ *
351
+ * @return Bronto_Api_Message
352
+ */
353
+ public function getMessageObject()
354
+ {
355
+ return $this->getObject('message');
356
+ }
357
+
358
+ /**
359
+ * Proxy for intellisense
360
+ *
361
+ * @return Bronto_Api_MessageRule
362
+ */
363
+ public function getMessageRuleObject()
364
+ {
365
+ return $this->getObject('messageRule');
366
+ }
367
+
368
+ /**
369
+ * Proxy for intellisense
370
+ *
371
+ * @return Bronto_Api_List
372
+ */
373
+ public function getListObject()
374
+ {
375
+ return $this->getObject('list');
376
+ }
377
+
378
+ /**
379
+ * Proxy for intellisense
380
+ *
381
+ * @return Bronto_Api_Login
382
+ */
383
+ public function getLoginObject()
384
+ {
385
+ return $this->getObject('login');
386
+ }
387
+
388
+ /**
389
+ * Proxy for intellisense
390
+ *
391
+ * @return Bronto_Api_Order
392
+ */
393
+ public function getOrderObject()
394
+ {
395
+ return $this->getObject('order');
396
+ }
397
+
398
+ /**
399
+ * Proxy for intellisense
400
+ *
401
+ * @return Bronto_Api_Segment
402
+ */
403
+ public function getSegmentObject()
404
+ {
405
+ return $this->getObject('segment');
406
+ }
407
+
408
+ /**
409
+ * Lazy loads our API objects
410
+ *
411
+ * @param string $object
412
+ * @return Bronto_Api_Object
413
+ */
414
+ public function getObject($object)
415
+ {
416
+ $object = ucfirst($object);
417
+
418
+ if (!isset($this->_classCache[$object])) {
419
+ $className = "Bronto_Api_{$object}";
420
+ if (class_exists($className)) {
421
+ $this->_classCache[$object] = new $className(array('api' => $this));
422
+ } else {
423
+ $this->throwException("Unable to load class: {$className}");
424
+ }
425
+ }
426
+
427
+ return $this->_classCache[$object];
428
+ }
429
+
430
+ /**
431
+ * @param bool $authenticate
432
+ * @return SoapClient
433
+ */
434
+ public function getSoapClient($authenticate = true)
435
+ {
436
+ if ($this->_soapClient == null) {
437
+ $this->_connected = false;
438
+ $soapClientClass = $this->getOption('soap_client', 'Bronto_SoapClient');
439
+ $this->_soapClient = new $soapClientClass(self::BASE_WSDL, array(
440
+ 'soap_version' => $this->_options['soap_version'],
441
+ 'compression' => $this->_options['compression'],
442
+ 'encoding' => $this->_options['encoding'],
443
+ 'trace' => $this->_options['trace'],
444
+ 'exceptions' => $this->_options['exceptions'],
445
+ 'cache_wsdl' => $this->_options['cache_wsdl'],
446
+ 'user_agent' => $this->_options['user_agent'],
447
+ 'features' => $this->_options['features'],
448
+ ));
449
+ $this->_soapClient->__setLocation(self::BASE_LOCATION);
450
+ $this->_connected = true;
451
+ if ($authenticate && !$this->_authenticated && $this->getToken()) {
452
+ $this->login();
453
+ }
454
+ }
455
+ return $this->_soapClient;
456
+ }
457
+
458
+ /**
459
+ * @return Bronto_Api
460
+ */
461
+ public function reset()
462
+ {
463
+ $this->_connected = false;
464
+ $this->_authenticated = false;
465
+ $this->_soapClient = null;
466
+ return $this;
467
+ }
468
+
469
+ /**
470
+ * @param bool $value
471
+ * @return Bronto_Api
472
+ */
473
+ public function setDebug($value)
474
+ {
475
+ return $this->_setOption('debug', (bool) $value);
476
+ }
477
+
478
+ /**
479
+ * @return bool
480
+ */
481
+ public function getDebug()
482
+ {
483
+ return (bool) $this->_options['debug'];
484
+ }
485
+
486
+ /**
487
+ * @param array $options
488
+ * @return Bronto_Util_Retryer_RetryerInterface
489
+ */
490
+ public function getRetryer(array $options = array())
491
+ {
492
+ if (!($this->_retryer instanceOf Bronto_Util_Retryer_RetryerInterface)) {
493
+ $options = array_merge($this->_options['retryer'], $options);
494
+ switch ($options['type']) {
495
+ case 'file':
496
+ $this->_retryer = new Bronto_Util_Retryer_FileRetryer($options);
497
+ break;
498
+ default:
499
+ return false;
500
+ break;
501
+ }
502
+ }
503
+
504
+ return $this->_retryer;
505
+ }
506
+
507
+ /**
508
+ * @return Bronto_Util_Retryer_RetryerInterface
509
+ */
510
+ public function getUuid()
511
+ {
512
+ if (!$this->_uuid) {
513
+ $this->_uuid = new Bronto_Util_Uuid();
514
+ }
515
+
516
+ return $this->_uuid;
517
+ }
518
+
519
+ /**
520
+ * @return bool
521
+ */
522
+ public function isConnected()
523
+ {
524
+ return (bool) $this->_connected;
525
+ }
526
+
527
+ /**
528
+ * @return bool
529
+ */
530
+ public function isAuthenticated()
531
+ {
532
+ return (bool) $this->_authenticated;
533
+ }
534
+
535
+ /**
536
+ * Seamlessly iterate over a rowset.
537
+ *
538
+ * @param Bronto_Api_Rowset $rowset
539
+ * @return Bronto_Api_Rowset_Iterator
540
+ */
541
+ public function iterate(Bronto_Api_Rowset $rowset)
542
+ {
543
+ return new Bronto_Api_Rowset_Iterator($rowset);
544
+ }
545
+
546
+ /**
547
+ * Retrieve request XML
548
+ *
549
+ * @return string
550
+ */
551
+ public function getLastRequest()
552
+ {
553
+ if ($this->_soapClient !== null) {
554
+ return $this->_soapClient->__getLastRequest();
555
+ }
556
+ return '';
557
+ }
558
+
559
+ /**
560
+ * Get response XML
561
+ *
562
+ * @return string
563
+ */
564
+ public function getLastResponse()
565
+ {
566
+ if ($this->_soapClient !== null) {
567
+ return $this->_soapClient->__getLastResponse();
568
+ }
569
+ return '';
570
+ }
571
+
572
+ /**
573
+ * Retrieve request headers
574
+ *
575
+ * @return string
576
+ */
577
+ public function getLastRequestHeaders()
578
+ {
579
+ if ($this->_soapClient !== null) {
580
+ return $this->_soapClient->__getLastRequestHeaders();
581
+ }
582
+ return '';
583
+ }
584
+
585
+ /**
586
+ * Retrieve response headers (as string)
587
+ *
588
+ * @return string
589
+ */
590
+ public function getLastResponseHeaders()
591
+ {
592
+ if ($this->_soapClient !== null) {
593
+ return $this->_soapClient->__getLastResponseHeaders();
594
+ }
595
+ return '';
596
+ }
597
+
598
+ /**
599
+ * @return array
600
+ */
601
+ public function __sleep()
602
+ {
603
+ return array(
604
+ '_token',
605
+ '_options',
606
+ );
607
+ }
608
+ }
lib/Bronto/Api/Account.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/accountobject
6
+ *
7
+ * @method Bronto_Api_Account_Row createRow() createRow(array $data)
8
+ */
9
+ class Bronto_Api_Account extends Bronto_Api_Object
10
+ {
11
+ /** Status */
12
+ const STATUS_UNRESTRICTED = 'unrestricted';
13
+ const STATUS_RESTRICTED = 'restricted';
14
+ const STATUS_INACTIVE = 'inactive';
15
+
16
+ /**
17
+ * @var array
18
+ */
19
+ protected $_methods = array(
20
+ 'addAccounts' => 'add',
21
+ 'readAccounts' => 'read',
22
+ 'updateAccounts' => 'update',
23
+ 'deleteAccounts' => 'delete',
24
+ );
25
+
26
+ /**
27
+ * @var array
28
+ */
29
+ protected $_options = array(
30
+ 'status' => array(
31
+ self::STATUS_UNRESTRICTED,
32
+ self::STATUS_RESTRICTED,
33
+ self::STATUS_INACTIVE,
34
+ ),
35
+ );
36
+
37
+ /**
38
+ * @param array $filter
39
+ * @param bool $includeInfo
40
+ * @param string $status
41
+ * @param int $pageNumber
42
+ * @return Bronto_Api_Rowset
43
+ */
44
+ public function readAll(array $filter = array(), $includeInfo = true, $status = null, $pageNumber = 1)
45
+ {
46
+ $params = array();
47
+ $params['filter'] = $filter;
48
+ $params['includeInfo'] = (bool) $includeInfo;
49
+ if (!empty($status)) {
50
+ $params['status'] = $status;
51
+ }
52
+ $params['pageNumber'] = (int) $pageNumber;
53
+ return $this->read($params);
54
+ }
55
+ }
lib/Bronto/Api/Account/Exception.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_Account_Exception extends Bronto_Api_Exception
4
+ {
5
+ const INVALID_SITE = 701; // The account is invalid.
6
+ const DUPLICATE_SITE = 702; // There is already an account with the name: %s
7
+ const INVALID_TOKEN = 703; // The API token was invalid.
8
+ const INVALID_TOKEN_SITE = 704; // The account specified for the token was invalid: %s
9
+ const INVALID_TOKEN_NAME = 705; // The name specified for the token was invalid: %s
10
+ }
lib/Bronto/Api/Account/Row.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @property-read string $id
5
+ * @property string $name
6
+ * @property string $status
7
+ * @property array $generalSettings
8
+ * @property array $contactInformation
9
+ * @property array $formatSettings
10
+ * @property array $brandingSettings
11
+ * @property array $repliesSettings
12
+ * @property array $allocations
13
+ * @method Bronto_Api_Account_Row read() read()
14
+ * @method Bronto_Api_Account_Row save() save()
15
+ * @method Bronto_Api_Account_Row delete() delete()
16
+ * @method Bronto_Api_Account getApiObject() getApiObject()
17
+ */
18
+ class Bronto_Api_Account_Row extends Bronto_Api_Row
19
+ {
20
+
21
+ }
lib/Bronto/Api/Activity.php ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/activityobject
6
+ */
7
+ class Bronto_Api_Activity extends Bronto_Api_Object
8
+ {
9
+ /** trackingType */
10
+ const TYPE_OPEN = 'open';
11
+ const TYPE_CLICK = 'click';
12
+ const TYPE_CONVERSION = 'conversion';
13
+ const TYPE_BOUNCE = 'bounce';
14
+ const TYPE_SEND = 'send';
15
+ const TYPE_UNSUBSCRIBE = 'unsubscribe';
16
+ const TYPE_VIEW = 'view';
17
+
18
+ /** bounceType */
19
+ const BOUNCE_HARD_CONN_PERM = 'conn_perm';
20
+ const BOUNCE_HARD_SUB_PERM = 'sub_perm';
21
+ const BOUNCE_HARD_CONTENT_PERM = 'content_perm';
22
+ const BOUNCE_SOFT_CONN_TEMP = 'conn_temp';
23
+ const BOUNCE_SOFT_SUB_TEMP = 'sub_temp';
24
+ const BOUNCE_SOFT_CONTENT_TEMP = 'content_temp';
25
+ const BOUNCE_SOFT_OTHER = 'other';
26
+
27
+ /**
28
+ * @var array
29
+ */
30
+ protected $_methods = array(
31
+ 'readActivities' => 'read',
32
+ );
33
+
34
+ /**
35
+ * @var array
36
+ */
37
+ protected $_options = array(
38
+ 'trackingType' => array(
39
+ self::TYPE_OPEN,
40
+ self::TYPE_CLICK,
41
+ self::TYPE_CONVERSION,
42
+ self::TYPE_BOUNCE,
43
+ self::TYPE_SEND,
44
+ self::TYPE_UNSUBSCRIBE,
45
+ self::TYPE_VIEW,
46
+ ),
47
+ 'readDirection' => array(
48
+ self::DIRECTION_FIRST,
49
+ self::DIRECTION_NEXT,
50
+ ),
51
+ 'bounceType' => array(
52
+ self::BOUNCE_HARD_CONN_PERM,
53
+ self::BOUNCE_HARD_SUB_PERM,
54
+ self::BOUNCE_HARD_CONTENT_PERM,
55
+ self::BOUNCE_SOFT_CONN_TEMP,
56
+ self::BOUNCE_SOFT_SUB_TEMP,
57
+ self::BOUNCE_SOFT_CONTENT_TEMP,
58
+ self::BOUNCE_SOFT_OTHER,
59
+ ),
60
+ );
61
+
62
+ /**
63
+ * The primary key column or columns.
64
+ *
65
+ * @var mixed
66
+ */
67
+ protected $_primary = array('activityDate', 'trackingType');
68
+
69
+ /**
70
+ * @var int
71
+ */
72
+ protected $_iteratorType = Bronto_Api_Rowset_Iterator::TYPE_STREAM;
73
+
74
+ /**
75
+ * The key(s) to use when paginating
76
+ *
77
+ * @var array
78
+ */
79
+ protected $_iteratorParams = array(
80
+ 'readDirection' => false,
81
+ 'start' => 'activityDate',
82
+ );
83
+
84
+ /**
85
+ * For many activities, caching the row objects saves tons of time.
86
+ * Example: fetching 1000 activities that references only 3 messageId's
87
+ *
88
+ * @var array
89
+ */
90
+ protected $_objectCache = array(
91
+ 'contact' => array(),
92
+ 'delivery' => array(),
93
+ 'message' => array(),
94
+ 'list' => array(),
95
+ );
96
+
97
+ /**
98
+ * @param string $startDate
99
+ * @param int $size
100
+ * @param string|array $types
101
+ * @param string $direction
102
+ * @param string|array $contactIds
103
+ * @return Bronto_Api_Rowset
104
+ */
105
+ public function readAll($startDate = '2002-01-01T00:00:00+00:00', $size = 1000, $types = array(), $direction = self::DIRECTION_FIRST, $contactIds = array())
106
+ {
107
+ $filter = array(
108
+ 'start' => '2002-01-01T00:00:00+00:00',
109
+ 'size' => 1000,
110
+ 'types' => $this->getOptionValues('trackingType'),
111
+ 'readDirection' => self::DIRECTION_FIRST,
112
+ 'contactIds' => array(),
113
+ );
114
+
115
+ if (!empty($startDate)) {
116
+ $filter['start'] = $startDate;
117
+ }
118
+
119
+ if (!empty($size)) {
120
+ $filter['size'] = $size < 1000 ? 1000 : (int) $size;
121
+ }
122
+
123
+ if (!empty($types)) {
124
+ if (is_array($types)) {
125
+ $filter['types'] = $types;
126
+ } else {
127
+ $filter['types'] = array($types);
128
+ }
129
+ }
130
+
131
+ $direction = strtoupper($direction);
132
+ if (in_array($direction, $this->_options['readDirection'])) {
133
+ $filter['readDirection'] = $direction;
134
+ }
135
+
136
+ if (!empty($contactIds)) {
137
+ if (is_array($contactIds)) {
138
+ $filter['contactIds'] = $contactIds;
139
+ } else {
140
+ $filter['contactIds'] = array($contactIds);
141
+ }
142
+ }
143
+
144
+ // @todo Remove if the contactIds filter is enabled again
145
+ unset($filter['contactIds']);
146
+
147
+ return parent::read(array('filter' => $filter));
148
+ }
149
+
150
+ /**
151
+ * @param array $data
152
+ */
153
+ public function createRow(array $data = array())
154
+ {
155
+ throw new Bronto_Api_Activity_Exception('You cannot create an Activity row.');
156
+ }
157
+
158
+ /**
159
+ * @param string $type
160
+ * @param string $index
161
+ * @param Bronto_Api_Row $object
162
+ */
163
+ public function addToCache($type, $index, Bronto_Api_Row $object)
164
+ {
165
+ // Conserve memory
166
+ while (count($this->_objectCache[$type]) >= 25) {
167
+ array_shift($this->_objectCache[$type]);
168
+ }
169
+
170
+ $this->_objectCache[$type][$index] = $object;
171
+ return $this;
172
+ }
173
+
174
+ /**
175
+ * @param string $type
176
+ * @param string $index
177
+ * @return bool|Bronto_Api_Row
178
+ */
179
+ public function getFromCache($type, $index)
180
+ {
181
+ if (isset($this->_objectCache[$type][$index])) {
182
+ return $this->_objectCache[$type][$index];
183
+ }
184
+ return false;
185
+ }
186
+
187
+ /**
188
+ * @param string $bounceType
189
+ * @return bool
190
+ */
191
+ public function isBounceHard($bounceType)
192
+ {
193
+ return (
194
+ $bounceType === self::BOUNCE_HARD_CONN_PERM ||
195
+ $bounceType === self::BOUNCE_HARD_SUB_PERM ||
196
+ $bounceType === self::BOUNCE_HARD_CONTENT_PERM
197
+ );
198
+ }
199
+
200
+ /**
201
+ * @param string $bounceType
202
+ * @return bool
203
+ */
204
+ public function isBounceSoft($bounceType)
205
+ {
206
+ return (
207
+ $bounceType === self::BOUNCE_SOFT_CONN_TEMP ||
208
+ $bounceType === self::BOUNCE_SOFT_SUB_TEMP ||
209
+ $bounceType === self::BOUNCE_SOFT_CONTENT_TEMP ||
210
+ $bounceType === self::BOUNCE_SOFT_OTHER
211
+ );
212
+ }
213
+ }
lib/Bronto/Api/Activity/Exception.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_Activity_Exception extends Bronto_Api_Exception
4
+ {
5
+ const INVALID_START_DATE = 1201; // Start date is invalid:
6
+ const INVALID_ACTIVITY_TYPE = 1202; // Invalid Activity types:
7
+ const INVALID_SIZE = 1203; // Activity size is invalid:
8
+ const NO_CONTACT_FILTER = 1204; // Activities cannot currently be filtered by contact ID
9
+ }
lib/Bronto/Api/Activity/Row.php ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @property-read string $activityDate
5
+ * @property-read string $contactId
6
+ * @property-read string $deliveryId
7
+ * @property-read string $messageId
8
+ * @property-read string $listId
9
+ * @property-read string $segmentId
10
+ * @property-read string $trackingType
11
+ * @property-read string $bounceReason
12
+ * @property-read string $bounceType
13
+ * @property-read string $linkName
14
+ * @property-read string $linkUrl
15
+ * @method bool isOpen() isOpen()
16
+ * @method bool isClick() isClick()
17
+ * @method bool isConversion() isConversion()
18
+ * @method bool isBounce() isBounce()
19
+ * @method bool isSend() isSend()
20
+ * @method bool isUnsubscribe() isUnsubscribe()
21
+ * @method bool isView() isView()
22
+ * @method Bronto_Api_Contact_Row getContact() getContact()
23
+ * @method Bronto_Api_Delivery_Row getDelivery() getDelivery()
24
+ * @method Bronto_Api_Message_Row getMessage() getMessage()
25
+ * @method Bronto_Api_List_Row getList() getList()
26
+ * @method Bronto_Api_Activity getApiObject() getApiObject()
27
+ */
28
+ class Bronto_Api_Activity_Row extends Bronto_Api_Row
29
+ {
30
+ /**
31
+ * Tracks columns that are dates.
32
+ *
33
+ * @var array
34
+ */
35
+ protected $_dateFields = array(
36
+ 'activityDate' => true
37
+ );
38
+
39
+ /**
40
+ * @var bool
41
+ */
42
+ protected $_readOnly = true;
43
+
44
+ /**
45
+ * @param string $name
46
+ * @param array $arguments
47
+ * @return Bronto_Api_Row
48
+ */
49
+ public function __call($name, $arguments)
50
+ {
51
+ // Check is{Type}
52
+ if (substr($name, 0, 2) == 'is') {
53
+ $type = strtolower(substr($name, 2));
54
+ if ($this->getApiObject()->isValidOptionValue('trackingType', $type)) {
55
+ return $this->trackingType == $type;
56
+ }
57
+ }
58
+
59
+ // Check get{Object}
60
+ if (substr($name, 0, 3) == 'get') {
61
+ $object = strtolower(substr($name, 3));
62
+ switch ($object) {
63
+ case 'contact':
64
+ case 'delivery':
65
+ case 'message':
66
+ case 'list':
67
+ // Cache object result
68
+ $cacheObject = (bool) (isset($arguments[0]) && $arguments[0]);
69
+ $idField = "{$object}Id";
70
+ if (isset($this->{$idField}) && !empty($this->{$idField})) {
71
+ if ($cacheObject) {
72
+ $cached = $this->getApiObject()->getFromCache($object, $this->{$idField});
73
+ if ($cached) {
74
+ return $cached;
75
+ }
76
+ }
77
+ $apiObject = $this->getApi()->getObject($object);
78
+ $row = $apiObject->createRow();
79
+ $row->id = $this->{$idField};
80
+ $row->read();
81
+ if ($cacheObject) {
82
+ $this->getApiObject()->addToCache($object, $this->{$idField}, $row);
83
+ }
84
+ return $row;
85
+ } else {
86
+ return false;
87
+ }
88
+ break;
89
+ }
90
+ }
91
+
92
+ throw new BadMethodCallException("The method {$name} does not exist");
93
+ }
94
+
95
+ /**
96
+ * @return boolean
97
+ */
98
+ public function isSoftBounce()
99
+ {
100
+ if ($this->isBounce()) {
101
+ return $this->getApiObject()->isBounceSoft($this->bounceType);
102
+ }
103
+
104
+ return false;
105
+ }
106
+
107
+ /**
108
+ * @return boolean
109
+ */
110
+ public function isHardBounce()
111
+ {
112
+ if ($this->isBounce()) {
113
+ return $this->getApiObject()->isBounceHard($this->bounceType);
114
+ }
115
+
116
+ return false;
117
+ }
118
+
119
+ /**
120
+ * @param mixed $upsert
121
+ * @param mixed $refresh
122
+ * @throws Bronto_Api_Activity_Exception
123
+ */
124
+ public function save($upsert = null, $refresh = null)
125
+ {
126
+ throw new Bronto_Api_Activity_Exception('You cannot create/update an Activity row.');
127
+ }
128
+
129
+ /**
130
+ * @throws Bronto_Api_Activity_Exception
131
+ */
132
+ public function delete()
133
+ {
134
+ throw new Bronto_Api_Activity_Exception('You cannot delete an Activity row.');
135
+ }
136
+ }
lib/Bronto/Api/ApiToken.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/apitokenobject
6
+ *
7
+ * @method Bronto_Api_ApiToken_Row createRow() createRow(array $data)
8
+ */
9
+ class Bronto_Api_ApiToken extends Bronto_Api_Object
10
+ {
11
+ /** Permissions */
12
+ const PERMISSION_NONE = 0;
13
+ const PERMISSION_READ = 1;
14
+ const PERMISSION_WRITE = 2;
15
+ const PERMISSION_SEND = 4;
16
+
17
+ /** Permissions Shortcuts */
18
+ const PERMISSIONS_READ_WRITE = 3;
19
+ const PERMISSIONS_READ_SEND = 5;
20
+ const PERMISSIONS_WRITE_SEND = 6;
21
+ const PERMISSIONS_READ_WRITE_SEND = 7;
22
+ const PERMISSIONS_ALL = self::PERMISSIONS_READ_WRITE_SEND;
23
+
24
+ /**
25
+ * @var array
26
+ */
27
+ protected $_options = array(
28
+ 'permissions' => array(
29
+ self::PERMISSION_READ,
30
+ self::PERMISSION_WRITE,
31
+ self::PERMISSION_SEND,
32
+ self::PERMISSIONS_READ_WRITE,
33
+ self::PERMISSIONS_READ_SEND,
34
+ self::PERMISSIONS_WRITE_SEND,
35
+ self::PERMISSIONS_READ_WRITE_SEND,
36
+ ),
37
+ );
38
+
39
+ /**
40
+ * @var array
41
+ */
42
+ protected $_methods = array(
43
+ 'addApiTokens' => 'add',
44
+ 'readApiTokens' => 'read',
45
+ 'updateApiTokens' => 'update',
46
+ 'deleteApiTokens' => 'delete',
47
+ );
48
+
49
+ /**
50
+ * @param array $filter
51
+ * @param int $pageNumber
52
+ * @return Bronto_Api_Rowset
53
+ */
54
+ public function readAll(array $filter = array(), $pageNumber = 1)
55
+ {
56
+ $params = array();
57
+ $params['filter'] = $filter;
58
+ $params['pageNumber'] = (int) $pageNumber;
59
+
60
+ $this->_validateParams($params);
61
+
62
+ return parent::read($params);
63
+ }
64
+
65
+ /**
66
+ * @param array $params
67
+ * @return bool
68
+ */
69
+ protected function _validateParams(array $params)
70
+ {
71
+ if (!isset($params['filter']) || !is_array($params['filter'])) {
72
+ throw new Bronto_Api_Exception('readApiTokens requires an filter array.');
73
+ }
74
+
75
+ $validFilters = array('id', 'accountId', 'name');
76
+ $hasValidFilter = false;
77
+ foreach ($params['filter'] as $key => $value) {
78
+ if (in_array($key, $validFilters)) {
79
+ $hasValidFilter = true;
80
+ break;
81
+ }
82
+ }
83
+
84
+ if (!$hasValidFilter) {
85
+ throw new Bronto_Api_Exception('readApiTokens requires a filter by one of: ' . implode(', ', $validFilters));
86
+ }
87
+
88
+ return true;
89
+ }
90
+
91
+ /**
92
+ * @param int $permissions
93
+ * @return array
94
+ */
95
+ public function getPermissionsLabels($permissions)
96
+ {
97
+ switch ($permissions) {
98
+ case Bronto_Api_ApiToken::PERMISSION_READ:
99
+ return array('read');
100
+ break;
101
+ case Bronto_Api_ApiToken::PERMISSION_WRITE:
102
+ return array('write');
103
+ break;
104
+ case Bronto_Api_ApiToken::PERMISSION_SEND:
105
+ return array('send');
106
+ break;
107
+ case Bronto_Api_ApiToken::PERMISSIONS_READ_WRITE:
108
+ return array('read', 'write');
109
+ break;
110
+ case Bronto_Api_ApiToken::PERMISSIONS_READ_SEND:
111
+ return array('read', 'send');
112
+ break;
113
+ case Bronto_Api_ApiToken::PERMISSIONS_WRITE_SEND:
114
+ return array('write', 'send');
115
+ break;
116
+ case Bronto_Api_ApiToken::PERMISSIONS_READ_WRITE_SEND:
117
+ return array('read', 'write', 'send');
118
+ break;
119
+ case Bronto_Api_ApiToken::PERMISSION_NONE:
120
+ return array('none');
121
+ break;
122
+ }
123
+
124
+ return false;
125
+ }
126
+ }
lib/Bronto/Api/ApiToken/Exception.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_ApiToken_Exception extends Bronto_Api_Exception
4
+ {
5
+
6
+ }
lib/Bronto/Api/ApiToken/Row.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @property-read string $id
5
+ * @property string $name
6
+ * @property int $permissions
7
+ * @property bool $active
8
+ * @property string $accountId
9
+ * @method Bronto_Api_ApiToken_Row save() save()
10
+ * @method Bronto_Api_ApiToken_Row delete() delete()
11
+ * @method Bronto_Api_ApiToken getApiObject() getApiObject()
12
+ */
13
+ class Bronto_Api_ApiToken_Row extends Bronto_Api_Row
14
+ {
15
+ /**
16
+ * @return Bronto_Api_ApiToken_Row
17
+ */
18
+ public function read()
19
+ {
20
+ if ($this->id) {
21
+ $params = array('id' => $this->id);
22
+ } elseif ($this->accountId) {
23
+ $params = array('accountId' => $this->accountId);
24
+ } elseif ($this->name) {
25
+ $params = array(
26
+ 'name' => array(
27
+ 'value' => $this->name,
28
+ 'operator' => 'EqualTo',
29
+ )
30
+ );
31
+ } else {
32
+ throw new Bronto_Api_ApiToken_Exception('Trying to read ApiToken without Id or Name for lookup');
33
+ }
34
+
35
+ parent::_read($params);
36
+ return $this;
37
+ }
38
+
39
+ /**
40
+ * @return Bronto_Api_Account_Row
41
+ */
42
+ public function getAccount()
43
+ {
44
+ if (!$this->accountId) {
45
+ if ($this->id || $this->name) {
46
+ $this->read();
47
+ }
48
+ if (!$this->accountId) {
49
+ throw new Bronto_Api_ApiToken_Exception('No accountId specified to retrieve Account');
50
+ }
51
+ }
52
+
53
+ $account = $this->getApi()->getAccountObject()->createRow();
54
+ $account->id = $this->accountId;
55
+ $account->read();
56
+
57
+ return $account;
58
+ }
59
+
60
+ /**
61
+ * @param int $permissions
62
+ * @return bool
63
+ */
64
+ public function hasPermissions($permissions)
65
+ {
66
+ if ($this->permissions === null) {
67
+ $this->read();
68
+ }
69
+
70
+ return $this->permissions >= $permissions;
71
+ }
72
+
73
+ /**
74
+ * @return array
75
+ */
76
+ public function getPermissionsLabels()
77
+ {
78
+ return $this->getApiObject()->getPermissionsLabels($this->permissions);
79
+ }
80
+ }
lib/Bronto/Api/Contact.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/contactobject
6
+ *
7
+ * @method Bronto_Api_Contact_Row createRow() createRow(array $data)
8
+ */
9
+ class Bronto_Api_Contact extends Bronto_Api_Object
10
+ {
11
+ /** Status */
12
+ const STATUS_ACTIVE = 'active';
13
+ const STATUS_ONBOARDING = 'onboarding';
14
+ const STATUS_TRANSACTIONAL = 'transactional';
15
+ const STATUS_BOUNCE = 'bounce';
16
+ const STATUS_UNCONFIRMED = 'unconfirmed';
17
+ const STATUS_UNSUBSCRIBED = 'unsub';
18
+
19
+ /** MsgPref */
20
+ const MSGPREF_TEXT = 'text';
21
+ const MSGPREF_HTML = 'html';
22
+
23
+ /** Source */
24
+ const SOURCE_MANUAL = 'manual';
25
+ const SOURCE_IMPORT = 'import';
26
+ const SOURCE_API = 'api';
27
+ const SOURCE_WEBFORM = 'webform';
28
+ const SOURCE_SALESFORCE = 'sforcereport';
29
+
30
+ /**
31
+ * @var array
32
+ */
33
+ protected $_methods = array(
34
+ 'addContacts' => 'add',
35
+ 'readContacts' => 'read',
36
+ 'updateContacts' => 'update',
37
+ 'deleteContacts' => 'delete',
38
+ 'addOrUpdateContacts' => 'addOrUpdate',
39
+ 'addToList' => true,
40
+ 'removeFromList' => true,
41
+ 'addContactsToWorkflow' => true,
42
+ 'addContactEvent' => true,
43
+ );
44
+
45
+ /**
46
+ * @var array
47
+ */
48
+ protected $_options = array(
49
+ 'msgPref' => array(
50
+ self::MSGPREF_TEXT,
51
+ self::MSGPREF_HTML,
52
+ ),
53
+ 'status' => array(
54
+ self::STATUS_ACTIVE,
55
+ self::STATUS_ONBOARDING,
56
+ self::STATUS_TRANSACTIONAL,
57
+ self::STATUS_BOUNCE,
58
+ self::STATUS_UNCONFIRMED,
59
+ self::STATUS_UNSUBSCRIBED,
60
+ ),
61
+ 'source' => array(
62
+ self::SOURCE_MANUAL,
63
+ self::SOURCE_IMPORT,
64
+ self::SOURCE_API,
65
+ self::SOURCE_WEBFORM,
66
+ self::SOURCE_SALESFORCE,
67
+ ),
68
+ );
69
+
70
+ /**
71
+ * @param array $filter
72
+ * @param array $fields
73
+ * @param bool $includeLists
74
+ * @param int $pageNumber
75
+ * @return Bronto_Api_Rowset
76
+ */
77
+ public function readAll($filter = array(), $fields = array(), $includeLists = true, $pageNumber = 1)
78
+ {
79
+ $params = array(
80
+ 'filter' => array(),
81
+ 'fields' => array(),
82
+ 'includeLists' => (bool) $includeLists,
83
+ 'pageNumber' => (int) $pageNumber,
84
+ );
85
+
86
+ if (!empty($filter)) {
87
+ if (is_array($filter)) {
88
+ $params['filter'] = $filter;
89
+ } else {
90
+ $params['filter'] = array($filter);
91
+ }
92
+ }
93
+
94
+ if (!empty($fields)) {
95
+ if (is_array($fields)) {
96
+ $params['fields'] = $fields;
97
+ } else {
98
+ $params['fields'] = array($fields);
99
+ }
100
+ }
101
+
102
+ return parent::read($params);
103
+ }
104
+ }
lib/Bronto/Api/Contact/Exception.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_Contact_Exception extends Bronto_Api_Exception
4
+ {
5
+ const INVALID_REQUEST = 301; // Invalid request:
6
+ const NOT_FOUND = 302; // Contact does not exist.
7
+ const INVALID_EMAIL = 303; // Invalid email address:
8
+ const INVALID_STATUS = 304; // Invalid status:
9
+ const ALREADY_EXISTS = 305; // Contact already exists:
10
+ const INVALID_FIELD = 306; // Invalid field attributes.
11
+ const MAX_SEARCH_ITEMS_EXCEEDED = 311; // The maximum number of contact search items was exceeded.
12
+ const MAX_SEARCH_LISTS_EXCEEDED = 312; // The maximum number of contact search lists was exceeded.
13
+ const MAX_SEARCH_SEGMENTS_EXCEEDED = 313; // The maximum number of contact search segments was exceeded.
14
+ const EMAIL_ALREADY_EXISTS = 314; // Email address already exists on another contact.
15
+ const EMAIL_SUPPRESSED = 315; // Email address is on suppression list.
16
+ const INVALID_EMAIL_LENGTH = 317; // Email address cannot exceed 100 characters in length:
17
+ const MOBILE_ALREADY_EXISTS = 318; // Mobile number already exists on another contact.
18
+ const INVALID_MOBILE = 319; // Invalid mobile number: %s
19
+ const MISSING_EMAIL_AND_MOBILE = 320; // Email address or mobile number is required.
20
+ }
lib/Bronto/Api/Contact/Row.php ADDED
@@ -0,0 +1,396 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @property-read string $id
5
+ * @property string $email
6
+ * @property string $mobileNumber
7
+ * @property string $status
8
+ * @property string $msgPref
9
+ * @property string $source
10
+ * @property string $customSource
11
+ * @property array $listIds
12
+ * @property array $fields
13
+ * @property-read string $created
14
+ * @property-read string $modifed
15
+ * @property-read bool $deleted
16
+ * @property-read int $numSends
17
+ * @property-read int $numBounces
18
+ * @property-read int $numOpens
19
+ * @property-read int $numClicks
20
+ * @property-read int $numConversions
21
+ * @property-read float $conversionAmount
22
+ * @method Bronto_Api_Contact_Row delete() delete()
23
+ * @method Bronto_Api_Contact getApiObject() getApiObject()
24
+ */
25
+ class Bronto_Api_Contact_Row extends Bronto_Api_Row implements Bronto_Api_Delivery_Recipient
26
+ {
27
+ /**
28
+ * @var array
29
+ */
30
+ protected $_data = array(
31
+ 'status' => Bronto_Api_Contact::STATUS_TRANSACTIONAL,
32
+ 'messagePrefence' => Bronto_Api_Contact::MSGPREF_HTML,
33
+ 'source' => Bronto_Api_Contact::SOURCE_API,
34
+ );
35
+
36
+ /**
37
+ * Initialize object
38
+ *
39
+ * Called from {@link __construct()} as final step of object instantiation.
40
+ */
41
+ public function init()
42
+ {
43
+ if (isset($this->_data['fields']) && is_array($this->_data['fields'])) {
44
+ foreach ($this->_data['fields'] as $i => $fieldRow) {
45
+ $this->_data['fields'][$i] = (array) $fieldRow;
46
+ }
47
+ $this->_cleanData = $this->_data;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * @return Bronto_Api_Contact_Row
53
+ */
54
+ public function read()
55
+ {
56
+ $params = array();
57
+ if ($this->id) {
58
+ $params = array('id' => $this->id);
59
+ } elseif ($this->email) {
60
+ $params = array(
61
+ 'email' => array(
62
+ 'value' => $this->email,
63
+ 'operator' => 'EqualTo',
64
+ )
65
+ );
66
+ } else {
67
+ throw new Bronto_Api_Contact_Exception('Trying to read Contact without Id or Email for lookup');
68
+ }
69
+
70
+ parent::_read($params);
71
+ return $this;
72
+ }
73
+
74
+ /**
75
+ * @param bool $upsert
76
+ * @param bool $refresh
77
+ * @return Bronto_Api_Contact_Row
78
+ */
79
+ public function save($upsert = true, $refresh = false)
80
+ {
81
+ try {
82
+ parent::_save($upsert, $refresh);
83
+ } catch (Bronto_Api_Contact_Exception $e) {
84
+ if ($e->getCode() === Bronto_Api_Contact_Exception::ALREADY_EXISTS) {
85
+ $this->_refresh();
86
+ } else {
87
+ $e->appendToMessage("(Email: {$this->email})");
88
+ $this->getApi()->throwException($e);
89
+ }
90
+ }
91
+
92
+ return $this;
93
+ }
94
+
95
+ /**
96
+ * @return Bronto_Api_Contact_Row
97
+ */
98
+ public function persist()
99
+ {
100
+ return parent::_persist('addOrUpdate', $this->email);
101
+ }
102
+
103
+ /**
104
+ * Sets a value for a custom Field
105
+ *
106
+ * @param string|Bronto_Api_Field_Row $field
107
+ * @param mixed $value
108
+ * @return Bronto_Api_Contact_Row
109
+ */
110
+ public function setField($field, $value)
111
+ {
112
+ if ($value === '') {
113
+ return;
114
+ }
115
+
116
+ $fieldId = $field;
117
+ if ($field instanceOf Bronto_Api_Field_Row) {
118
+ if (!$field->id) {
119
+ $field = $field->read();
120
+ }
121
+ $fieldId = $field->id;
122
+
123
+ switch ($field->type) {
124
+ case Bronto_Api_Field::TYPE_DATE:
125
+ if ($value instanceOf DateTime) {
126
+ $value = date('c', $value->getTimestamp());
127
+ } else {
128
+ $value = date('c', strtotime($value));
129
+ }
130
+ break;
131
+ case Bronto_Api_Field::TYPE_INTEGER:
132
+ $value = (int) $value;
133
+ break;
134
+ case Bronto_Api_Field::TYPE_FLOAT:
135
+ $value = (float) $value;
136
+ break;
137
+ }
138
+ }
139
+
140
+ $field = array(
141
+ 'fieldId' => $fieldId,
142
+ 'content' => $value,
143
+ );
144
+
145
+ if (!isset($this->_data['fields']) || !is_array($this->_data['fields'])) {
146
+ $this->_data['fields'] = array();
147
+ } else {
148
+ // Check for dupes
149
+ foreach ($this->_data['fields'] as $i => $_field) {
150
+ if ($_field['fieldId'] == $field['fieldId']) {
151
+ $this->_data['fields'][$i] = $field;
152
+ $this->_modifiedFields['fields'] = true;
153
+ return $this;
154
+ }
155
+ }
156
+ }
157
+
158
+ $this->_data['fields'][] = $field;
159
+ $this->_modifiedFields['fields'] = true;
160
+ return $this;
161
+ }
162
+
163
+ /**
164
+ * Retreives a value for a custom field
165
+ * NOTE: Loads the field for you if it hasn't been requested
166
+ *
167
+ * @param string|Bronto_Api_Field_Row $field $field
168
+ * @return mixed
169
+ */
170
+ public function getField($field)
171
+ {
172
+ $fieldId = $field;
173
+ if ($field instanceOf Bronto_Api_Field_Row) {
174
+ if (!$field->id) {
175
+ $field = $field->read();
176
+ }
177
+ $fieldId = $field->id;
178
+ }
179
+
180
+ // Determine if we have the field already
181
+ if (isset($this->_data['fields']) && is_array($this->_data['fields'])) {
182
+ foreach ($this->_data['fields'] as $i => $fieldRow) {
183
+ if ($fieldRow['fieldId'] == $fieldId) {
184
+ return $fieldRow['content'];
185
+ }
186
+ }
187
+ }
188
+
189
+ // We don't, so request it
190
+ if ($this->id) {
191
+ try {
192
+ if ($rowset = $this->getApiObject()->readAll(array('id' => $this->id), array($fieldId))) {
193
+ foreach ($rowset as $row) {
194
+ $data = $row->getData();
195
+ if (is_array($data) && !empty($data) && isset($data['fields'])) {
196
+ $this->_data['fields'] = array_merge(
197
+ isset($this->_data['fields']) ? $this->_data['fields'] : array(),
198
+ $data['fields']
199
+ );
200
+ $this->_cleanData = $this->_data;
201
+ break;
202
+ }
203
+ }
204
+ }
205
+ } catch (Exception $e) {
206
+ return false;
207
+ }
208
+ }
209
+
210
+ // Try the traverse again
211
+ if (isset($this->_data['fields']) && is_array($this->_data['fields'])) {
212
+ foreach ($this->_data['fields'] as $i => $fieldRow) {
213
+ if ($fieldRow['fieldId'] == $fieldId) {
214
+ return $fieldRow['content'];
215
+ }
216
+ }
217
+ }
218
+
219
+ // Something went horribly wrong
220
+ return null;
221
+ }
222
+
223
+ /**
224
+ * @return array
225
+ */
226
+ public function getLists()
227
+ {
228
+ if ($this->id) {
229
+ $filter = array('id' => $this->id);
230
+ } else {
231
+ $filter = array(
232
+ 'email' => array(
233
+ 'value' => $this->email,
234
+ 'operator' => 'EqualTo',
235
+ )
236
+ );
237
+ }
238
+
239
+ try {
240
+ $rowset = $this->getApiObject()->readAll($filter, array(), true);
241
+
242
+ if ($rowset->count() > 0) {
243
+ $data = $rowset->current()->getData();
244
+ if (isset($data['listIds'])) {
245
+ return $data['listIds'];
246
+ }
247
+ }
248
+ } catch (Exception $e) {
249
+ // Ignore
250
+ }
251
+
252
+ return array();
253
+ }
254
+
255
+ /**
256
+ * @param Bronto_Api_List_Row|string $list
257
+ * @return Bronto_Api_Contact_Row
258
+ */
259
+ public function addToList($list)
260
+ {
261
+ $listId = $list;
262
+ if ($list instanceOf Bronto_Api_List_Row) {
263
+ if (!$list->id) {
264
+ $list = $list->read();
265
+ }
266
+ $listId = $list->id;
267
+ }
268
+
269
+ if (!isset($this->_data['listIds'])) {
270
+ $this->_loadLists();
271
+ }
272
+
273
+ if (!in_array($listId, $this->_data['listIds'])) {
274
+ $this->_data['listIds'][] = $listId;
275
+ $this->_modifiedFields['listIds'] = true;
276
+ }
277
+ return $this;
278
+ }
279
+
280
+ /**
281
+ * @param Bronto_Api_List_Row|string $list
282
+ * @return Bronto_Api_Contact_Row
283
+ */
284
+ public function removeFromList($list)
285
+ {
286
+ $listId = $list;
287
+ if ($list instanceOf Bronto_Api_List_Row) {
288
+ if (!$list->id) {
289
+ $list = $list->read();
290
+ }
291
+ $listId = $list->id;
292
+ }
293
+
294
+ if (!isset($this->_data['listIds'])) {
295
+ $this->_loadLists();
296
+ }
297
+
298
+ if (is_array($this->_data['listIds'])) {
299
+ foreach ($this->_data['listIds'] as $i => $id) {
300
+ if ($id == $listId) {
301
+ unset($this->_data['listIds'][$i]);
302
+ break;
303
+ }
304
+ }
305
+ }
306
+
307
+ $this->_modifiedFields['listIds'] = true;
308
+ return $this;
309
+ }
310
+
311
+ /**
312
+ * @return void
313
+ */
314
+ protected function _loadLists()
315
+ {
316
+ if (!isset($this->_data['listIds'])) {
317
+ $this->_data['listIds'] = array();
318
+ }
319
+
320
+ $listIds = $this->getLists();
321
+ foreach ($listIds as $listId) {
322
+ $this->_data['listIds'][] = $listId;
323
+ $this->_modifiedFields['listIds'] = true;
324
+ }
325
+ }
326
+
327
+ /**
328
+ * @param array $additionalFilter
329
+ * @param int $pageNumber
330
+ * @return Bronto_Api_Rowset
331
+ */
332
+ public function getDeliveries(array $additionalFilter = array(), $pageNumber = 1)
333
+ {
334
+ if (!$this->id) {
335
+ $exceptionClass = $this->getExceptionClass();
336
+ throw new $exceptionClass("This Contact has not been retrieved yet (has no ContactId)");
337
+ }
338
+
339
+ /* @var $deliveryObject Bronto_Api_Delivery */
340
+ $deliveryObject = $this->getApi()->getDeliveryObject();
341
+ $filter = array_merge_recursive(array('contactId' => $this->id), $additionalFilter);
342
+ return $deliveryObject->readDeliveryRecipients($filter, $pageNumber);
343
+ }
344
+
345
+ /**
346
+ * Set row field value
347
+ *
348
+ * @param string $columnName The column key.
349
+ * @param mixed $value The value for the property.
350
+ */
351
+ public function __set($columnName, $value)
352
+ {
353
+ switch (strtolower($columnName)) {
354
+ case 'email':
355
+ // Trim whitespace
356
+ $value = preg_replace('/\s+/', '', $value);
357
+ // Check if email got truncated
358
+ if (substr($value, -1) === '.') {
359
+ $value .= 'com';
360
+ }
361
+ break;
362
+ }
363
+
364
+ return parent::__set($columnName, $value);
365
+ }
366
+
367
+ /**
368
+ * Required by Bronto_Api_Delivery_Recipient
369
+ *
370
+ * @return false
371
+ */
372
+ public function isList()
373
+ {
374
+ return false;
375
+ }
376
+
377
+ /**
378
+ * Required by Bronto_Api_Delivery_Recipient
379
+ *
380
+ * @return true
381
+ */
382
+ public function isContact()
383
+ {
384
+ return true;
385
+ }
386
+
387
+ /**
388
+ * Required by Bronto_Api_Delivery_Recipient
389
+ *
390
+ * @return false
391
+ */
392
+ public function isSegment()
393
+ {
394
+ return false;
395
+ }
396
+ }
lib/Bronto/Api/Conversion.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/conversionobject
6
+ *
7
+ * @method Bronto_Api_Conversion_Row createRow() createRow(array $data = array())
8
+ */
9
+ class Bronto_Api_Conversion extends Bronto_Api_Object
10
+ {
11
+ /**
12
+ * @var array
13
+ */
14
+ protected $_methods = array(
15
+ 'addConversion' => 'add',
16
+ 'readConversions' => 'read',
17
+ );
18
+
19
+ /**
20
+ * @param array $filter
21
+ * @param int $pageNumber
22
+ * @return Bronto_Api_Rowset
23
+ */
24
+ public function readAll(array $filter = array(), $pageNumber = 1)
25
+ {
26
+ $params = array(
27
+ 'filter' => array(),
28
+ 'pageNumber' => (int) $pageNumber,
29
+ );
30
+
31
+ if (!empty($filter)) {
32
+ if (is_array($filter)) {
33
+ $params['filter'] = $filter;
34
+ } else {
35
+ $params['filter'] = array($filter);
36
+ }
37
+ } else {
38
+ $params['filter'] = array('contactId' => array());
39
+ }
40
+
41
+ return parent::read($params);
42
+ }
43
+ }
lib/Bronto/Api/Conversion/Exception.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_Conversion_Exception extends Bronto_Api_Exception
4
+ {
5
+ const DUPLICATE_ORDER = 901; // Duplicate Order Id: %%id%%.
6
+ const MISSING_AMOUNT = 902; // Missing required field: amount.
7
+ const MISSING_QUANTITY = 903; // Missing required field: quantity.
8
+ }
lib/Bronto/Api/Conversion/Row.php ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @property-read string $id
5
+ * @property string $contactId
6
+ * @property string $email
7
+ * @property string $orderId
8
+ * @property string $item
9
+ * @property string $description
10
+ * @property int $quantity
11
+ * @property float $amount
12
+ * @property float $orderTotal
13
+ * @property string $createdDate
14
+ * @property string $deliveryId
15
+ * @property string $messageId
16
+ * @property string $automatorId
17
+ * @property string $listId
18
+ * @property string $segmentId
19
+ * @property string $deliveryType
20
+ * @property-write string $tid
21
+ * @method Bronto_Api_Conversion getApiObject() getApiObject()
22
+ */
23
+ class Bronto_Api_Conversion_Row extends Bronto_Api_Row
24
+ {
25
+ /**
26
+ * @return Bronto_Api_Conversion_Row
27
+ */
28
+ public function read()
29
+ {
30
+ $params = array();
31
+
32
+ if ($this->id) {
33
+ $params['id'] = array($this->id);
34
+ } else {
35
+ if ($this->contactId) {
36
+ $params['contactId'] = array($this->contactId);
37
+ }
38
+
39
+ if ($this->deliveryId) {
40
+ $params['deliveryId'] = array($this->deliveryId);
41
+ }
42
+
43
+ if ($this->orderId) {
44
+ $params['orderId'] = array($this->orderId);
45
+ }
46
+ }
47
+
48
+ parent::_read($params);
49
+ return $this;
50
+ }
51
+
52
+ /**
53
+ * @param bool $upsert Ignored
54
+ * @param bool $refresh
55
+ * @return Bronto_Api_Conversion_Row
56
+ */
57
+ public function save($upsert = null, $refresh = false)
58
+ {
59
+ /**
60
+ * If the _cleanData array is empty,
61
+ * this is an ADD of a new row.
62
+ * Otherwise it is an UPDATE.
63
+ */
64
+ if (empty($this->_cleanData)) {
65
+ parent::_save(false, $refresh);
66
+ } else {
67
+ throw new Bronto_Api_Row_Exception(sprintf("Cannot update a %s record.", $this->getApiObject()->getName()));
68
+ }
69
+
70
+ return $this;
71
+ }
72
+
73
+ /**
74
+ * @return Bronto_Api_Conversion_Row
75
+ */
76
+ public function persist()
77
+ {
78
+ return parent::_persist('add', false);
79
+ }
80
+
81
+ /**
82
+ * Set row field value
83
+ *
84
+ * @param string $columnName The column key.
85
+ * @param mixed $value The value for the property.
86
+ */
87
+ public function __set($columnName, $value)
88
+ {
89
+ switch (strtolower($columnName)) {
90
+ case 'email':
91
+ // Trim whitespace
92
+ $value = preg_replace('/\s+/', '', $value);
93
+ // Check if email got truncated
94
+ if (substr($value, -1) === '.') {
95
+ $value .= 'com';
96
+ }
97
+ break;
98
+ }
99
+
100
+ return parent::__set($columnName, $value);
101
+ }
102
+ }
lib/Bronto/Api/Delivery.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/deliveryobject
6
+ *
7
+ * @method Bronto_Api_Delivery_Row createRow() createRow(array $data = array())
8
+ */
9
+ class Bronto_Api_Delivery extends Bronto_Api_Object
10
+ {
11
+ /** Status */
12
+ const STATUS_SENT = 'sent';
13
+ const STATUS_SENDING = 'sending';
14
+ const STATUS_UNSENT = 'unsent';
15
+ const STATUS_ARCHIVED = 'archived';
16
+ const STATUS_SKIPPED = 'skipped';
17
+
18
+ /** Type */
19
+ const TYPE_NORMAL = 'normal';
20
+ const TYPE_TEST = 'test';
21
+ const TYPE_TRANSACTIONAL = 'transactional';
22
+ const TYPE_AUTOMATED = 'automated';
23
+
24
+ /**
25
+ * @var array
26
+ */
27
+ protected $_methods = array(
28
+ 'addDeliveries' => 'add',
29
+ 'readDeliveries' => 'read',
30
+ 'updateDeliveries' => 'update',
31
+ 'deleteDeliveries' => 'delete',
32
+ 'readDeliveryRecipients' => true,
33
+ );
34
+
35
+ /**
36
+ * @var array
37
+ */
38
+ protected $_options = array(
39
+ 'status' => array(
40
+ self::STATUS_SENT,
41
+ self::STATUS_SENDING,
42
+ self::STATUS_UNSENT,
43
+ self::STATUS_ARCHIVED,
44
+ self::STATUS_SKIPPED,
45
+ ),
46
+ 'type' => array(
47
+ self::TYPE_NORMAL,
48
+ self::TYPE_TEST,
49
+ self::TYPE_TRANSACTIONAL,
50
+ self::TYPE_AUTOMATED,
51
+ ),
52
+ );
53
+
54
+ /**
55
+ * @param array $filter
56
+ * @param bool $includeRecipients
57
+ * @param bool $includeContent
58
+ * @param int $pageNumber
59
+ * @return Bronto_Api_Rowset
60
+ */
61
+ public function readAll(array $filter = array(), $includeRecipients = false, $includeContent = false, $pageNumber = 1)
62
+ {
63
+ $params = array();
64
+ $params['filter'] = $filter;
65
+ $params['includeRecipients'] = (bool) $includeRecipients;
66
+ $params['includeContent'] = (bool) $includeContent;
67
+ $params['pageNumber'] = (int) $pageNumber;
68
+ return $this->read($params);
69
+ }
70
+
71
+ /**
72
+ * @param array $filter
73
+ * @param int $pageNumber
74
+ * @return Bronto_Api_Rowset
75
+ */
76
+ public function readDeliveryRecipients(array $filter = array(), $pageNumber = 1)
77
+ {
78
+ $params = array();
79
+ $params['filter'] = $filter;
80
+ $params['pageNumber'] = (int) $pageNumber;
81
+ return $this->doRequest('readDeliveryRecipients', $params);
82
+ }
83
+ }
lib/Bronto/Api/Delivery/Exception.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_Delivery_Exception extends Bronto_Api_Exception
4
+ {
5
+ const INVALID_SEND_DATE = 201; // The send date is invalid.
6
+ const INVALID_FROM_ADDRESS = 202; // The from address is invalid.
7
+ const FATAL_ERROR_SEND = 203; // Fatal error sending delivery.
8
+ const INVALID_RECIPIENT_TYPE = 204; // The recipient type is invalid.
9
+ const INVALID_MESSAGE = 205; // The delivery message was not found:
10
+ const INVALID_LIST = 206; // The list for this delivery was not found:
11
+ const INVALID_SEGMENT = 207; // The segment for this delivery was not found:
12
+ const INVALID_SUBSCRIBER = 208; // The subscriber for this delivery was not found:
13
+ const NO_RECIPIENTS = 209; // Your delivery has no recipients.
14
+ const INVALID_FROM_NAME = 213; // The from name is invalid.
15
+ const MESSAGE_NOT_TRANSACTIONAL_APPROVED = 215; // Message not approved for transactional sending:
16
+ const MESSAGE_FIELD_MISSING_POSITION = 216; // Missing required position in message field name: %s
17
+ const NONUNIQUE_MESSAGE_FIELD_POSITION = 217; // Position must be unique in message field name: %s
18
+ const NOT_FOUND = 219; // Delivery does not exist: %s
19
+ const INVALID_THROTTLE = 220; // Throttle rate must be in range [0, 720] (minutes)
20
+ }
lib/Bronto/Api/Delivery/Recipient.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface Bronto_Api_Delivery_Recipient
4
+ {
5
+ /**
6
+ * @return bool
7
+ */
8
+ public function isList();
9
+
10
+ /**
11
+ * @return bool
12
+ */
13
+ public function isContact();
14
+
15
+ /**
16
+ * @return bool
17
+ */
18
+ public function isSegment();
19
+ }
lib/Bronto/Api/Delivery/Row.php ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @property-read string $id
5
+ * @property string start
6
+ * @property string $messageId
7
+ * @property string $status
8
+ * @property string $type
9
+ * @property string $fromEmail
10
+ * @property string $fromName
11
+ * @property bool $authentication
12
+ * @property bool $replyTracking
13
+ * @property string $replyEmail
14
+ * @property string $messageRuleId
15
+ * @property bool $optin
16
+ * @property float $throttle
17
+ * @property array $content
18
+ * @property array $recipients
19
+ * @property array $fields
20
+ * @property-read int $numSends
21
+ * @property-read int $numDeliveries
22
+ * @property-read int $numHardBadEmail
23
+ * @property-read int $numHardDestUnreach
24
+ * @property-read int $numHardMessageContent
25
+ * @property-read int $numHardBounces
26
+ * @property-read int $numSoftBadEmail
27
+ * @property-read int $numSoftDestUnreach
28
+ * @property-read int $numSoftMessageContent
29
+ * @property-read int $numSoftBounces
30
+ * @property-read int $numOtherBounces
31
+ * @property-read int $uniqOpens
32
+ * @property-read int $numOpens
33
+ * @property-read int $avgOpens
34
+ * @property-read int $uniqClicks
35
+ * @property-read int $numClicks
36
+ * @property-read int $avgClicks
37
+ * @property-read int $uniqConversions
38
+ * @property-read int $numConversions
39
+ * @property-read int $avgConversions
40
+ * @property-read int $revenue
41
+ * @property-read int $numSurveyResponses
42
+ * @property-read int $numFriendForwards
43
+ * @property-read int $numContactUpdates
44
+ * @property-read int $numUnsubscribesByPrefs
45
+ * @property-read int $numUnsubscribesByComplaint
46
+ * @property-read int $numContactLoss
47
+ * @property-read int $numContactLossBounces
48
+ * @property-read float $deliveryRate
49
+ * @property-read float $openRate
50
+ * @property-read float $clickRate
51
+ * @property-read float $clickThroughRate
52
+ * @property-read float $conversionRate
53
+ * @property-read float $bounceRate
54
+ * @property-read float $complaintRate
55
+ * @property-read float $contactLossRate
56
+ * @property-read int $numSocialShares
57
+ * @property-read int $sharesFacebook
58
+ * @property-read int $sharesTwitter
59
+ * @property-read int $sharesLinkedIn
60
+ * @property-read int $sharesDigg
61
+ * @property-read int $sharesMySpace
62
+ * @property-read int $viewsFacebook
63
+ * @property-read int $viewsTwitter
64
+ * @property-read int $viewsLinkedIn
65
+ * @property-read int $viewsDigg
66
+ * @property-read int $viewsMySpace
67
+ * @property-read int $numSocialViews
68
+ * @method Bronto_Api_Delivery_Row read() read()
69
+ * @method Bronto_Api_Delivery_Row delete() delete()
70
+ * @method Bronto_Api_Delivery getApiObject() getApiObject()
71
+ */
72
+ class Bronto_Api_Delivery_Row extends Bronto_Api_Row
73
+ {
74
+ /**
75
+ * @var array
76
+ */
77
+ protected $_recipients = array();
78
+
79
+ /**
80
+ * @param bool $refresh
81
+ * @param array $additionalFilter
82
+ * @return array
83
+ */
84
+ public function getRecipients($refresh = false, array $additionalFilter = array())
85
+ {
86
+ if (!$this->id) {
87
+ $exceptionClass = $this->getExceptionClass();
88
+ throw new $exceptionClass("This Delivery has not been retrieved yet (has no DeliveryId)");
89
+ }
90
+
91
+ // If we have already retrieved this, don't do it again
92
+ if (!empty($this->_recipients) && !$refresh) {
93
+ return $this->_recipients;
94
+ }
95
+
96
+ // We didn't do $includeRecipients = true from original request
97
+ if (empty($this->recipients)) {
98
+ $this->recipients = array();
99
+
100
+ $filter = array();
101
+ $filter['deliveryId'] = $this->id;
102
+ $filter = array_merge($additionalFilter, $filter);
103
+ $recipientPage = 1;
104
+ while ($recipients = $this->getApiObject()->readDeliveryRecipients($filter, $recipientPage)) {
105
+ if (!$recipients->count()) {
106
+ break;
107
+ }
108
+
109
+ $this->recipients = $this->recipients + $recipients;
110
+ $recipientPage++;
111
+ }
112
+ }
113
+
114
+ $this->_recipients = array();
115
+ if (!empty($this->recipients)) {
116
+ foreach ($this->recipients as $i => $recipient) {
117
+ switch ($recipient->type) {
118
+ case 'list':
119
+ $listObject = $this->getApi()->getListObject();
120
+ $list = $listObject->createRow();
121
+ $list->id = $recipient->id;
122
+ $this->_recipients[] = $list;
123
+ break;
124
+ case 'contact':
125
+ $contactObject = $this->getApi()->getContactObject();
126
+ $contact = $contactObject->createRow();
127
+ $contact->id = $recipient->id;
128
+ $this->_recipients[] = $contact;
129
+ break;
130
+ case 'segment':
131
+ $segmentObject = $this->getApi()->getSegmentObject();
132
+ $segment = $segmentObject->createRow();
133
+ $segment->id = $recipient->id;
134
+ $this->_recipients[] = $segment;
135
+ break;
136
+ default:
137
+ $exceptionClass = $this->getExceptionClass();
138
+ throw new $exceptionClass("Recipient type '{$recipient->type}' is not currently supported");
139
+ break;
140
+ }
141
+ }
142
+ }
143
+
144
+ return $this->_recipients;
145
+ }
146
+
147
+ /**
148
+ * @param Bronto_Api_DeliveryGroup_Row|string $$deliveryGroup
149
+ * @return bool
150
+ */
151
+ public function addToDeliveryGroup($deliveryGroup)
152
+ {
153
+ if (!$this->id) {
154
+ $exceptionClass = $this->getExceptionClass();
155
+ throw new $exceptionClass("This Delivery has not been saved yet (has no DeliveryId)");
156
+ }
157
+
158
+ $deliveryGroupId = $deliveryGroup;
159
+ if ($deliveryGroup instanceOf Bronto_Api_DeliveryGroup_Row) {
160
+ if (!$deliveryGroup->id) {
161
+ $deliveryGroup = $deliveryGroup->read();
162
+ }
163
+ $deliveryGroupId = $deliveryGroup->id;
164
+ }
165
+
166
+ if (empty($deliveryGroupId)) {
167
+ $exceptionClass = $this->getExceptionClass();
168
+ throw new $exceptionClass('Unable to find deliveryGroup');
169
+ }
170
+
171
+ $deliveryGroupObject = $this->getApi()->getDeliveryGroupObject();
172
+ return $deliveryGroupObject->addToDeliveryGroup($deliveryGroupId, array($this->id));
173
+ }
174
+
175
+ /**
176
+ * Sets a value for a Message Field
177
+ *
178
+ * @param string $$field
179
+ * @param mixed $value
180
+ * @param string $$type text|html
181
+ * @return Bronto_Api_Delivery_Row
182
+ */
183
+ public function setField($field, $value, $type = 'html')
184
+ {
185
+ if (strlen($field) > 25) {
186
+ // Make sure we don't pass a field name longer than 25 characters
187
+ $field = substr($field, 0, 25);
188
+ }
189
+
190
+ $messageField = array(
191
+ 'name' => $field,
192
+ 'type' => $type,
193
+ 'content' => $value,
194
+ );
195
+
196
+ if (!isset($this->_data['fields']) || !is_array($this->_data['fields'])) {
197
+ $this->_data['fields'] = array();
198
+ } else {
199
+ // Check for dupes
200
+ foreach ($this->_data['fields'] as $i => $_field) {
201
+ if ($_field['name'] == $messageField['name']) {
202
+ $this->_data['fields'][$i] = $messageField;
203
+ $this->_modifiedFields['fields'] = true;
204
+ return $this;
205
+ }
206
+ }
207
+ }
208
+
209
+ $this->_data['fields'][] = $messageField;
210
+ $this->_modifiedFields['fields'] = true;
211
+ return $this;
212
+ }
213
+
214
+ /**
215
+ * @return array
216
+ */
217
+ public function getFields()
218
+ {
219
+ if (!empty($this->_data['fields'])) {
220
+ return $this->_data['fields'];
221
+ }
222
+ return array();
223
+ }
224
+
225
+ /**
226
+ * @param bool $upsert Ignored
227
+ * @param bool $refresh
228
+ * @return Bronto_Api_Delivery_Row
229
+ */
230
+ public function save($upsert = null, $refresh = false)
231
+ {
232
+ parent::_save(false, $refresh);
233
+ return $this;
234
+ }
235
+ }
lib/Bronto/Api/DeliveryGroup.php ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/deliverygroupobject
6
+ *
7
+ * @method Bronto_Api_DeliveryGroup_Row createRow() createRow(array $data = array())
8
+ */
9
+ class Bronto_Api_DeliveryGroup extends Bronto_Api_Object
10
+ {
11
+ /** Visibility */
12
+ const VISIBILITY_INTERNAL = 'INTERNAL';
13
+ const VISIBILITY_PUBLIC = 'PUBLIC';
14
+
15
+ /** memberType */
16
+ const MEMBER_TYPE_DELIVERIES = 'DELIVERIES';
17
+ const MEMBER_TYPE_AUTOMATORS = 'AUTOMATORS';
18
+ const MEMBER_TYPE_MESSAGEGROUPS = 'MESSAGEGROUPS';
19
+ const MEMBER_TYPE_DELIVERYGROUPS = 'DELIVERYGROUPS';
20
+
21
+ /**
22
+ * The object name.
23
+ *
24
+ * @var string
25
+ */
26
+ protected $_name = 'DeliveryGroup';
27
+
28
+ /**
29
+ * @var array
30
+ */
31
+ protected $_methods = array(
32
+ 'addDeliveryGroup' => 'add',
33
+ 'readDeliveryGroups' => 'read',
34
+ 'updateDeliveryGroup' => 'update',
35
+ 'deleteDeliveryGroup' => 'delete',
36
+ 'addOrUpdateDeliveryGroup' => 'addOrUpdate',
37
+ 'addToDeliveryGroup' => true,
38
+ 'deleteFromDeliveryGroup' => true,
39
+ );
40
+
41
+ /**
42
+ * @var array
43
+ */
44
+ protected $_options = array(
45
+ 'visibility' => array(
46
+ self::VISIBILITY_INTERNAL,
47
+ self::VISIBILITY_PUBLIC,
48
+ ),
49
+ 'memberType' => array(
50
+ self::MEMBER_TYPE_DELIVERIES,
51
+ self::MEMBER_TYPE_AUTOMATORS,
52
+ self::MEMBER_TYPE_MESSAGEGROUPS,
53
+ self::MEMBER_TYPE_DELIVERYGROUPS,
54
+ ),
55
+ );
56
+
57
+ /**
58
+ * @param array $filter
59
+ * @param int $pageNumber
60
+ * @return Bronto_Api_Rowset
61
+ */
62
+ public function readAll(array $filter = array(), $pageNumber = 1)
63
+ {
64
+ $params = array();
65
+ $params['filter'] = $filter;
66
+ $params['pageNumber'] = (int) $pageNumber;
67
+ return $this->read($params);
68
+ }
69
+
70
+ /**
71
+ * @param string $deliveryGroupId
72
+ * @param array $deliveryIds
73
+ * @param array $messageIds
74
+ * @param array $messageRuleIds
75
+ * @return Bronto_Api_Rowset
76
+ */
77
+ public function addToDeliveryGroup($deliveryGroupId, array $deliveryIds = array(), array $messageIds = array(), array $messageRuleIds = array())
78
+ {
79
+ $data = array(
80
+ 'deliveryGroup' => array('id' => $deliveryGroupId),
81
+ );
82
+
83
+ if (!empty($deliveryIds)) {
84
+ $data['deliveryIds'] = $deliveryIds;
85
+ }
86
+
87
+ if (!empty($messageIds)) {
88
+ $data['messageIds'] = $messageIds;
89
+ }
90
+
91
+ if (!empty($messageRuleIds)) {
92
+ $data['messageRuleIds'] = $messageRuleIds;
93
+ }
94
+
95
+ return $this->doRequest('addToDeliveryGroup', $data);
96
+ }
97
+ }
lib/Bronto/Api/DeliveryGroup/Exception.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_DeliveryGroup_Exception extends Bronto_Api_Exception
4
+ {
5
+ const INVALID_DELIVERYGROUP = 801; // The specified deliverygroup was invalid.
6
+ const DELIVERYGROUP_NO_ID = 802; // No ID provided for deliverygroup.
7
+ const DELIVERYGROUP_DOES_NOT_EXIST = 803; // Specified deliverygroup (id=%s) does not exist.
8
+ const DELIVERYGROUP_ADD_FAIL = 804; // Failed to add deliverygroup.
9
+ const DELIVERYGROUP_LIST_FAIL = 805; // Failed to list %s for deliverygroup (id=%s).
10
+ const DELIVERYGROUP_ID_FAIL = 806; // Failed to find %s with id=%s in deliverygroup.
11
+ const DELIVERYGROUP_IDS_FAIL = 807; // Failed to find %s in deliverygroup.
12
+ const DELIVERYGROUP_DELETE_FAIL = 808; // Failed to remove deliverygroup.
13
+ const DELIVERYGROUP_ADD_MEMBER_FAIL = 809; // Failed to add element to deliverygroup.
14
+ const DELIVERYGROUP_DELETE_MEMBER_FAIL = 810; // Failed to remove element from deliverygroup.
15
+ const DELIVERYGROUP_SEARCH_FAIL = 811; // Search failed for query=%s.
16
+ const DELIVERYGROUP_UPDATE_FAIL = 812; // Failed to update deliverygroup.
17
+ const DELIVERYGROUP_CREATED_ADD_MEMBER_FAIL = 813; // Created deliverygroup but failed to add one or more elements to it
18
+ }
lib/Bronto/Api/DeliveryGroup/Row.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @property-read string $id
5
+ * @property string $name
6
+ * @property string $visibility
7
+ * @property int $deliveryCount
8
+ * @property string $createdDate
9
+ * @property array $deliveryIds
10
+ * @property array $messageRuleIds
11
+ * @property array $messageIds
12
+ * @method Bronto_Api_DeliveryGroup getApiObject() getApiObject()
13
+ */
14
+ class Bronto_Api_DeliveryGroup_Row extends Bronto_Api_Row
15
+ {
16
+ /**
17
+ * @return Bronto_Api_DeliveryGroup_Row
18
+ */
19
+ public function read()
20
+ {
21
+ if ($this->id) {
22
+ $params = array('id' => $this->id);
23
+ } elseif ($this->name) {
24
+ $params = array(
25
+ 'name' => array(
26
+ 'value' => $this->name,
27
+ 'operator' => 'EqualTo',
28
+ )
29
+ );
30
+ }
31
+
32
+ parent::_read($params);
33
+ return $this;
34
+ }
35
+
36
+ /**
37
+ * @param bool $upsert
38
+ * @param bool $refresh
39
+ * @return Bronto_Api_DeliveryGroup_Row
40
+ */
41
+ public function save($upsert = true, $refresh = false)
42
+ {
43
+ if (!$upsert) {
44
+ parent::_save(false, $refresh);
45
+ }
46
+
47
+ try {
48
+ parent::_save(true, $refresh);
49
+ } catch (Bronto_Api_DeliveryGroup_Exception $e) {
50
+ $this->getApi()->throwException($e);
51
+ }
52
+
53
+ return $this;
54
+ }
55
+ }
lib/Bronto/Api/Exception.php ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ */
6
+ class Bronto_Api_Exception extends Exception
7
+ {
8
+ const UNKNOWN_ERROR = 101; // There was an unknown API error. Please try your request again shortly.
9
+ const INVALID_TOKEN = 102; // Authentication failed for token:
10
+ const INVALID_SESSION_TOKEN = 103; // Your session is invalid. Please log in again.
11
+ const INVALID_ACCESS = 104; // You do not have valid access for this method.
12
+ const INVALID_INPUT_ARRAY = 105; // You must specify at least one item in the input array.
13
+ const INVALID_PARAMETER = 106; // Unable to verify parameter:
14
+ const INVALID_REQUEST = 107; // There was an error in your soap request. Please examine the request and try again.
15
+ const SHARD_OFFLINE = 108; // The API is currently undergoing maintenance. Please try your request again later.
16
+ const SITE_INACTIVE = 109; // This site is currently marked as 'inactive'
17
+ const REQUIRED_FIELDS = 110; // Required fields are missing:
18
+ const UNAUTHORIZED_IP = 111; // Your IP address does not have access for token.
19
+ const INVALID_FILTER = 112; // Invalid filter type (must be AND or OR).
20
+ const READ_ERROR = 113; // There was an error reading your query results. Please try your request again shortly.
21
+
22
+ const INVALID_PAGE_SIZE = 115; // Page size is lower than the minimum allowed limit of #
23
+
24
+ /* Misc */
25
+ const HTTP_HEADER_ERROR = 98001; // Error Fetching http headers
26
+ const NO_XML_DOCUMENT = 98002;
27
+ const INVALID_URL = 98003;
28
+ const CONNECT_ERROR = 98004;
29
+ const WSDL_PARSE_ERROR = 98005; // SOAP-ERROR: Parsing WSDL
30
+ const REQUEST_ERROR = 98006;
31
+ const CONNECTION_RESET = 98007; // SSL: Connection reset by peer
32
+ const CONNECTION_FAILED = 98008; // Could not connect to host
33
+ const SERVICE_UNAVAILABLE = 98009; // Service Temporarily Unavailable
34
+ const SOAPCLIENT_ERROR = 98010; // SoapClient::__doRequest(): %s
35
+ const SERVER_ERROR = 98500; // Internal Server Error
36
+
37
+ /* Custom */
38
+ const EMPTY_RESULT = 99001;
39
+ const NO_TOKEN = 99002;
40
+
41
+ /**
42
+ * Array of exceptions we can (maybe) recover from
43
+ * @var array
44
+ */
45
+ protected $_recoverable = array(
46
+ self::UNKNOWN_ERROR,
47
+ self::INVALID_SESSION_TOKEN,
48
+ self::INVALID_REQUEST,
49
+ self::SHARD_OFFLINE,
50
+ self::READ_ERROR,
51
+ self::HTTP_HEADER_ERROR,
52
+ self::NO_XML_DOCUMENT,
53
+ self::CONNECT_ERROR,
54
+ self::WSDL_PARSE_ERROR,
55
+ self::CONNECTION_RESET,
56
+ self::CONNECTION_FAILED,
57
+ self::SERVICE_UNAVAILABLE,
58
+ self::SERVER_ERROR,
59
+ self::SOAPCLIENT_ERROR,
60
+ );
61
+
62
+ /**
63
+ * @var string
64
+ */
65
+ protected $_request;
66
+
67
+ /**
68
+ * @var string
69
+ */
70
+ protected $_response;
71
+
72
+ /**
73
+ * For PHP <5.3.0
74
+ *
75
+ * @var Exception
76
+ */
77
+ protected $_previous;
78
+
79
+ /**
80
+ * @param string $message
81
+ * @param string $code
82
+ * @param int $tries
83
+ * @param Exception $previous
84
+ */
85
+ public function __construct($message = '', $code = 0, $tries = null, Exception $previous = null)
86
+ {
87
+ if (empty($code)) {
88
+ $parts = explode(':', $message, 2);
89
+ if (is_array($parts)) {
90
+ $parts = array_map('trim', $parts);
91
+ }
92
+ if (isset($parts[0]) && is_numeric($parts[0])) {
93
+ $code = (int) $parts[0];
94
+ $message = (string) $parts[1];
95
+ }
96
+ }
97
+
98
+ if (empty($code)) {
99
+ // Handle some SoapFault exceptions
100
+ if (stripos($message, 'Error Fetching http headers') !== false) {
101
+ $code = self::HTTP_HEADER_ERROR;
102
+ } else if (stripos($message, 'looks like we got no XML document') !== false) {
103
+ $code = self::NO_XML_DOCUMENT;
104
+ } else if (stripos($message, 'Could not connect to host') !== false) {
105
+ $code = self::CONNECT_ERROR;
106
+ } else if (stripos($message, 'Parsing WSDL') !== false) {
107
+ $code = self::WSDL_PARSE_ERROR;
108
+ } else if (stripos($message, 'There was an error in your soap request') !== false) {
109
+ $code = self::REQUEST_ERROR;
110
+ } else if (stripos($message, 'Connection reset by peer') !== false) {
111
+ $code = self::CONNECTION_RESET;
112
+ } else if (stripos($message, 'Unable to parse URL') !== false) {
113
+ $code = self::INVALID_URL;
114
+ } else if (stripos($message, 'Could not connect to host') !== false) {
115
+ $code = self::CONNECTION_FAILED;
116
+ } else if (stripos($message, 'Service Temporarily Unavailable') !== false) {
117
+ $code = self::SERVICE_UNAVAILABLE;
118
+ } else if (stripos($message, 'Internal Server Error') !== false) {
119
+ $code = self::SERVER_ERROR;
120
+ } else if (stripos($message, 'SoapClient::__doRequest()') !== false) {
121
+ $code = self::SOAPCLIENT_ERROR;
122
+ }
123
+ }
124
+
125
+ if (!empty($code)) {
126
+ $message = "{$code} : {$message}";
127
+ }
128
+
129
+ if (!empty($tries) && $tries > 1) {
130
+ $message .= " [Tried: {$tries}]";
131
+ }
132
+
133
+ if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
134
+ parent::__construct($message, $code, $previous);
135
+ } else {
136
+ $this->_previous = $previous;
137
+ parent::__construct($message, $code);
138
+ }
139
+ }
140
+
141
+ /**
142
+ * @param string $message
143
+ */
144
+ public function setMessage($message)
145
+ {
146
+ $this->message = $message;
147
+ }
148
+
149
+ /**
150
+ * @param string $text
151
+ */
152
+ public function appendToMessage($text)
153
+ {
154
+ $this->message .= " {$text}";
155
+ }
156
+
157
+ /**
158
+ * @return bool
159
+ */
160
+ public function isRecoverable()
161
+ {
162
+ if (!$this->getCode()) {
163
+ return false;
164
+ }
165
+ return in_array($this->getCode(), $this->_recoverable);
166
+ }
167
+
168
+ /**
169
+ * @param string $request
170
+ * @return Bronto_Api_Exception
171
+ */
172
+ public function setRequest($request)
173
+ {
174
+ $this->_request = $request;
175
+ return $this;
176
+ }
177
+
178
+ /**
179
+ * @return string
180
+ */
181
+ public function getRequest()
182
+ {
183
+ return $this->_request;
184
+ }
185
+
186
+ /**
187
+ * @param string $response
188
+ * @return Bronto_Api_Exception
189
+ */
190
+ public function setResponse($response)
191
+ {
192
+ $this->_response = $response;
193
+ }
194
+
195
+ /**
196
+ * @return string
197
+ */
198
+ public function getResponse()
199
+ {
200
+ return $this->_response;
201
+ }
202
+
203
+ /**
204
+ * For PHP <5.3.0
205
+ * @return Exception|null
206
+ */
207
+ public function getPreviousException()
208
+ {
209
+ if (method_exists($this, 'getPrevious')) {
210
+ return $this->getPrevious();
211
+ }
212
+ return $this->getPreviousException();
213
+ }
214
+
215
+ /**
216
+ * @return array
217
+ */
218
+ public function getTraceSafe()
219
+ {
220
+ if (!isset($this->_trace)) {
221
+ $this->_trace = $this->getTrace();
222
+ if (empty($this->_trace)) {
223
+ $backtrace = debug_backtrace();
224
+ $this->_trace = array($backtrace[count($backtrace)-1]);
225
+ }
226
+ }
227
+ return $this->_trace;
228
+ }
229
+
230
+ /**
231
+ * @return string
232
+ */
233
+ public function getErrorClass()
234
+ {
235
+ $trace = $this->getTraceSafe();
236
+ return $trace[0]['class'];
237
+ }
238
+
239
+ /**
240
+ * @return string
241
+ */
242
+ public function getErrorMethod()
243
+ {
244
+ $trace = $this->getTraceSafe();
245
+ return $trace[0]['function'];
246
+ }
247
+ }
lib/Bronto/Api/Field.php ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/fieldobject
6
+ *
7
+ * @method Bronto_Api_Field_Row createRow() createRow(array $data = array())
8
+ */
9
+ class Bronto_Api_Field extends Bronto_Api_Object
10
+ {
11
+ /** Type */
12
+ const TYPE_TEXT = 'text';
13
+ const TYPE_TEXTAREA = 'textarea';
14
+ const TYPE_PASSWORD = 'password';
15
+ const TYPE_CHECKBOX = 'checkbox';
16
+ const TYPE_RADIO = 'radio';
17
+ const TYPE_SELECT = 'select';
18
+ const TYPE_INTEGER = 'integer';
19
+ const TYPE_CURRENCY = 'currency';
20
+ const TYPE_FLOAT = 'float';
21
+ const TYPE_DATE = 'date';
22
+
23
+ /**
24
+ * @var array
25
+ */
26
+ protected $_methods = array(
27
+ 'addFields' => 'add',
28
+ 'readFields' => 'read',
29
+ 'updateFields' => 'update',
30
+ 'deleteFields' => 'delete',
31
+ );
32
+
33
+ /**
34
+ * @var array
35
+ */
36
+ protected $_options = array(
37
+ 'type' => array(
38
+ self::TYPE_TEXT,
39
+ self::TYPE_TEXTAREA,
40
+ self::TYPE_PASSWORD,
41
+ self::TYPE_CHECKBOX,
42
+ self::TYPE_RADIO,
43
+ self::TYPE_SELECT,
44
+ self::TYPE_INTEGER,
45
+ self::TYPE_CURRENCY,
46
+ self::TYPE_FLOAT,
47
+ self::TYPE_DATE,
48
+ ),
49
+ );
50
+
51
+ /**
52
+ * @var array
53
+ */
54
+ protected $_objectCache = array();
55
+
56
+ /**
57
+ * @param array $filter
58
+ * @param int $pageNumber
59
+ * @return Bronto_Api_Rowset
60
+ */
61
+ public function readAll(array $filter = array(), $pageNumber = 1)
62
+ {
63
+ $params = array();
64
+ $params['filter'] = $filter;
65
+ $params['pageNumber'] = (int) $pageNumber;
66
+ return $this->read($params);
67
+ }
68
+
69
+ /**
70
+ * @param string $index
71
+ * @param Bronto_Api_Field_Row $field
72
+ * @return Bronto_Api_Field
73
+ */
74
+ public function addToCache($index, Bronto_Api_Field_Row $field)
75
+ {
76
+ $this->_objectCache[$index] = $field;
77
+ return $this;
78
+ }
79
+
80
+ /**
81
+ * @param string $index
82
+ * @return Bronto_Api_Field_Row
83
+ */
84
+ public function getFromCache($index)
85
+ {
86
+ if (isset($this->_objectCache[$index]) && $this->_objectCache[$index] instanceOf Bronto_Api_Field_Row) {
87
+ return $this->_objectCache[$index];
88
+ }
89
+ return false;
90
+ }
91
+
92
+ /**
93
+ * @param string $name
94
+ * @return string
95
+ */
96
+ public function normalize($name)
97
+ {
98
+ $name = strtolower($name);
99
+ $name = preg_replace("/[^a-z\d_]/i", '_', $name);
100
+ $name = trim(preg_replace('/_+/', '_', $name), '_');
101
+
102
+ return $name;
103
+ }
104
+
105
+ /**
106
+ * @param string $name
107
+ * @param array $values
108
+ */
109
+ public function guessType($name, array $values)
110
+ {
111
+ // Check predefined fields first
112
+ if (isset(Bronto_Api_Field_Predefined::$normalizerMap[$name])) {
113
+ if (isset(Bronto_Api_Field_Predefined::$predefinedFields[$name])) {
114
+ return array(
115
+ $name => Bronto_Api_Field_Predefined::$predefinedFields[$name]
116
+ );
117
+ }
118
+ } else {
119
+ foreach (Bronto_Api_Field_Predefined::$normalizerMap as $key => $synonyms) {
120
+ if (in_array($name, $synonyms)) {
121
+ return array(
122
+ $key => Bronto_Api_Field_Predefined::$predefinedFields[$key]
123
+ );
124
+ }
125
+ }
126
+ }
127
+
128
+ // Try to type guess
129
+ $typeGuesser = new Bronto_Api_Field_TypeGuesser();
130
+ $typeGuesser->processValues($values);
131
+ return $typeGuesser->getChoice();
132
+ }
133
+ }
lib/Bronto/Api/Field/Exception.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_Field_Exception extends Bronto_Api_Exception
4
+ {
5
+ const INVALID_FIELD = 401; // The specified field was invalid.
6
+ const ALREADY_EXISTS = 402; // A field with this name already exists.
7
+ const INVALID_DISPLAY = 403; // The specified field type was invalid:
8
+ const INVALID_NAME = 404; // The field name was missing or invalid.
9
+ const INVALID_VISIBILITY = 405; // The specified field visibility was invalid.
10
+ const ALLOCATION_EXCEED = 408; // This operation would exceed your field allocation of %d.
11
+ const INVALID_FIELD_VALUE = 409; // The value specified for the field %%id%% was invalid.
12
+ const DATA_TRUNCATION = 410; // The value specified for the field %%id%% was too large.
13
+ const SEGMENT_DEPENDENCY = 411; // The field cannot be deleted because a segment depends upon it.
14
+ }
lib/Bronto/Api/Field/Predefined.php ADDED
@@ -0,0 +1,303 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ */
6
+ class Bronto_Api_Field_Predefined
7
+ {
8
+ /** Predefined Fields */
9
+ const FIELD_EMAIL = 'email';
10
+ const FIELD_SALUTATION = 'salutation';
11
+ const FIELD_FIRSTNAME = 'firstname';
12
+ const FIELD_LASTNAME = 'lastname';
13
+ const FIELD_AGE = 'age';
14
+ const FIELD_GENDER = 'gender';
15
+ const FIELD_BIRTHDAY = 'birthday';
16
+ const FIELD_ADDRESS1 = 'address1';
17
+ const FIELD_ADDRESS2 = 'address2';
18
+ const FIELD_CITY = 'city';
19
+ const FIELD_STATE = 'state';
20
+ const FIELD_STATE_ABBR = 'state_abbrev';
21
+ const FIELD_STATE_ABBR_UC = 'state_abbrev_uc';
22
+ const FIELD_STATE_PROVINCE = 'state_province';
23
+ const FIELD_POSTAL_CODE = 'postal_code';
24
+ const FIELD_COUNTRY = 'country';
25
+ const FIELD_COUNTRY_CODE = 'country_code';
26
+ const FIELD_PHONE_HOME = 'phone_home';
27
+ const FIELD_PHONE_WORK = 'phone_work';
28
+ const FIELD_PHONE_MOBILE = 'phone_mobile';
29
+ const FIELD_NUM_CHILDREN = 'num_children';
30
+ const FIELD_EDUCATION = 'education';
31
+ const FIELD_MARITAL_STATUS = 'marital_status';
32
+
33
+ /**
34
+ * @var array
35
+ */
36
+ public static $predefinedFields = array(
37
+ self::FIELD_SALUTATION => array(
38
+ 'label' => 'Salutation',
39
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
40
+ ),
41
+ self::FIELD_FIRSTNAME => array(
42
+ 'label' => 'First Name',
43
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
44
+ ),
45
+ self::FIELD_LASTNAME => array(
46
+ 'label' => 'Last Name',
47
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
48
+ ),
49
+ self::FIELD_AGE => array(
50
+ 'label' => 'Age',
51
+ 'type' => Bronto_Api_Field::TYPE_INTEGER,
52
+ ),
53
+ self::FIELD_GENDER => array(
54
+ 'label' => 'Gender',
55
+ 'type' => Bronto_Api_Field::TYPE_RADIO,
56
+ 'options' => array(
57
+ array(
58
+ 'value' => 'male',
59
+ 'isDefault' => false,
60
+ ),
61
+ array(
62
+ 'value' => 'female',
63
+ 'isDefault' => false,
64
+ ),
65
+ ),
66
+ ),
67
+ self::FIELD_BIRTHDAY => array(
68
+ 'label' => 'Birthday',
69
+ 'type' => Bronto_Api_Field::TYPE_DATE,
70
+ ),
71
+ self::FIELD_ADDRESS1 => array(
72
+ 'label' => 'Address',
73
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
74
+ ),
75
+ self::FIELD_ADDRESS2 => array(
76
+ 'label' => 'Address (Contd.)',
77
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
78
+ ),
79
+ self::FIELD_CITY => array(
80
+ 'label' => 'City',
81
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
82
+ ),
83
+ self::FIELD_STATE => array(
84
+ 'label' => 'State',
85
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
86
+ ),
87
+ self::FIELD_STATE_ABBR => array(
88
+ 'label' => 'State (Two-Letter Abbreviation)',
89
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
90
+ ),
91
+ self::FIELD_STATE_ABBR_UC => array(
92
+ 'label' => 'State (Uppercase Two-Letter Abbreviation)',
93
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
94
+ ),
95
+ self::FIELD_STATE_PROVINCE => array(
96
+ 'label' => 'State or Province',
97
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
98
+ ),
99
+ self::FIELD_POSTAL_CODE => array(
100
+ 'label' => 'Postal/ZIP Code',
101
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
102
+ ),
103
+ self::FIELD_COUNTRY => array(
104
+ 'label' => 'Country',
105
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
106
+ ),
107
+ self::FIELD_COUNTRY_CODE => array(
108
+ 'label' => 'Country',
109
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
110
+ ),
111
+ self::FIELD_PHONE_HOME => array(
112
+ 'label' => 'Home Phone',
113
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
114
+ ),
115
+ self::FIELD_PHONE_WORK => array(
116
+ 'label' => 'Work Phone',
117
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
118
+ ),
119
+ self::FIELD_PHONE_MOBILE => array(
120
+ 'label' => 'Mobile / Cell Phone',
121
+ 'type' => Bronto_Api_Field::TYPE_TEXT,
122
+ ),
123
+ self::FIELD_NUM_CHILDREN => array(
124
+ 'label' => 'Number of Children',
125
+ 'type' => Bronto_Api_Field::TYPE_SELECT,
126
+ 'options' => array(
127
+ array(
128
+ 'value' => 'None (0)',
129
+ 'isDefault' => true,
130
+ ),
131
+ array(
132
+ 'value' => '1',
133
+ 'isDefault' => false,
134
+ ),
135
+ array(
136
+ 'value' => '2',
137
+ 'isDefault' => false,
138
+ ),
139
+ array(
140
+ 'value' => '3',
141
+ 'isDefault' => false,
142
+ ),
143
+ array(
144
+ 'value' => '4',
145
+ 'isDefault' => false,
146
+ ),
147
+ array(
148
+ 'value' => '5',
149
+ 'isDefault' => false,
150
+ ),
151
+ array(
152
+ 'value' => '6',
153
+ 'isDefault' => false,
154
+ ),
155
+ array(
156
+ 'value' => '7',
157
+ 'isDefault' => false,
158
+ ),
159
+ array(
160
+ 'value' => '8',
161
+ 'isDefault' => false,
162
+ ),
163
+ array(
164
+ 'value' => '9',
165
+ 'isDefault' => false,
166
+ ),
167
+ array(
168
+ 'value' => '10',
169
+ 'isDefault' => false,
170
+ ),
171
+ ),
172
+ ),
173
+ self::FIELD_EDUCATION => array(
174
+ 'label' => 'Highest Level of Education',
175
+ 'type' => Bronto_Api_Field::TYPE_SELECT,
176
+ 'options' => array(
177
+ array(
178
+ 'value' => 'somehighschool',
179
+ 'isDefault' => false,
180
+ ),
181
+ array(
182
+ 'value' => 'highschool',
183
+ 'isDefault' => false,
184
+ ),
185
+ array(
186
+ 'value' => 'somecollege',
187
+ 'isDefault' => false,
188
+ ),
189
+ array(
190
+ 'value' => 'college',
191
+ 'isDefault' => false,
192
+ ),
193
+ array(
194
+ 'value' => 'somegraduate',
195
+ 'isDefault' => false,
196
+ ),
197
+ array(
198
+ 'value' => 'graduate',
199
+ 'isDefault' => false,
200
+ ),
201
+ ),
202
+ ),
203
+ self::FIELD_MARITAL_STATUS => array(
204
+ 'label' => 'Marital Status',
205
+ 'type' => Bronto_Api_Field::TYPE_SELECT,
206
+ 'options' => array(
207
+ array(
208
+ 'value' => 'single',
209
+ 'isDefault' => false,
210
+ ),
211
+ array(
212
+ 'value' => 'married',
213
+ 'isDefault' => false,
214
+ ),
215
+ array(
216
+ 'value' => 'divorced',
217
+ 'isDefault' => false,
218
+ ),
219
+ array(
220
+ 'value' => 'widowed',
221
+ 'isDefault' => false,
222
+ ),
223
+ ),
224
+ ),
225
+ );
226
+
227
+ /**
228
+ * @var array
229
+ */
230
+ public static $normalizerMap = array(
231
+ self::FIELD_EMAIL => array(
232
+ 'email_address',
233
+ 'emailaddress',
234
+ ),
235
+ self::FIELD_SALUTATION => array(),
236
+ self::FIELD_FIRSTNAME => array(
237
+ 'first_name',
238
+ 'fname',
239
+ ),
240
+ self::FIELD_LASTNAME => array(
241
+ 'last_name',
242
+ 'lname',
243
+ ),
244
+ self::FIELD_AGE => array(),
245
+ self::FIELD_GENDER => array(),
246
+ self::FIELD_BIRTHDAY => array(
247
+ 'birth_day',
248
+ 'birth_date',
249
+ 'dob',
250
+ 'birthdate',
251
+ 'dateofbirth',
252
+ 'date_of_birth',
253
+ ),
254
+ self::FIELD_ADDRESS1 => array(
255
+ 'address_line1',
256
+ 'addressline1',
257
+ 'address_1',
258
+ ),
259
+ self::FIELD_ADDRESS2 => array(
260
+ 'address_line2',
261
+ 'addressline2',
262
+ 'address_2',
263
+ ),
264
+ self::FIELD_CITY => array(
265
+ 'cityname',
266
+ 'city_name',
267
+ ),
268
+ self::FIELD_STATE => array(),
269
+ self::FIELD_STATE_ABBR => array(),
270
+ self::FIELD_STATE_ABBR_UC => array(),
271
+ self::FIELD_STATE_PROVINCE => array(),
272
+ self::FIELD_POSTAL_CODE => array(
273
+ 'zipcode',
274
+ 'zip',
275
+ 'postcode',
276
+ 'postalcode',
277
+ 'zip_code',
278
+ ),
279
+ self::FIELD_COUNTRY => array(),
280
+ self::FIELD_COUNTRY_CODE => array(),
281
+ self::FIELD_PHONE_HOME => array(
282
+ 'phonehome',
283
+ 'home_phone',
284
+ 'phone',
285
+ 'homephone',
286
+ ),
287
+ self::FIELD_PHONE_WORK => array(
288
+ 'phonework',
289
+ 'work_phone',
290
+ 'workphone',
291
+ ),
292
+ self::FIELD_PHONE_MOBILE => array(
293
+ 'mobile',
294
+ 'mobile_phone',
295
+ 'cell',
296
+ 'cellphone',
297
+ 'mobilephone',
298
+ ),
299
+ self::FIELD_NUM_CHILDREN => array(),
300
+ self::FIELD_EDUCATION => array(),
301
+ self::FIELD_MARITAL_STATUS => array(),
302
+ );
303
+ }
lib/Bronto/Api/Field/Row.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @property-read string $id
5
+ * @property string $name
6
+ * @property string $label
7
+ * @property string $type
8
+ * @property string $visibility
9
+ * @property array $options
10
+ * @method Bronto_Api_Field_Row delete() delete()
11
+ * @method Bronto_Api_Field getApiObject() getApiObject()
12
+ */
13
+ class Bronto_Api_Field_Row extends Bronto_Api_Row
14
+ {
15
+ /**
16
+ * @return Bronto_Api_Field_Row
17
+ */
18
+ public function read()
19
+ {
20
+ if ($this->id) {
21
+ $params = array('id' => $this->id);
22
+ } elseif ($this->name) {
23
+ $params = array(
24
+ 'name' => array(
25
+ 'value' => $this->name,
26
+ 'operator' => 'EqualTo',
27
+ )
28
+ );
29
+ }
30
+
31
+ parent::_read($params);
32
+ return $this;
33
+ }
34
+
35
+ /**
36
+ * @param bool $upsert
37
+ * @param bool $refresh
38
+ * @return Bronto_Api_Field_Row
39
+ */
40
+ public function save($upsert = true, $refresh = false)
41
+ {
42
+ if (!$upsert) {
43
+ parent::_save(false, $refresh);
44
+ }
45
+
46
+ try {
47
+ parent::_save(true, $refresh);
48
+ } catch (Bronto_Api_Field_Exception $e) {
49
+ if ($e->getCode() === Bronto_Api_Field_Exception::ALREADY_EXISTS) {
50
+ $this->_refresh();
51
+ } else {
52
+ $e->appendToMessage("(Name: {$this->name})");
53
+ $this->getApi()->throwException($e);
54
+ }
55
+ }
56
+
57
+ return $this;
58
+ }
59
+ }
lib/Bronto/Api/Field/TypeGuesser.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ */
6
+ class Bronto_Api_Field_TypeGuesser
7
+ {
8
+ const DEFAULT_CHOICE = 'text';
9
+ const CONFIDENCE_THRESHOLD = 70;
10
+
11
+ /**
12
+ * @var int
13
+ */
14
+ protected $_total = 0;
15
+
16
+ /**
17
+ * @var array
18
+ */
19
+ protected $_guesses = array();
20
+
21
+ /**
22
+ * @var array
23
+ */
24
+ protected $_defaultGuesses = array(
25
+ 'text' => 0,
26
+ 'integer' => 0,
27
+ 'currency' => 0,
28
+ 'float' => 0,
29
+ 'date' => 0,
30
+ );
31
+
32
+ /**
33
+ * @return text
34
+ */
35
+ public function getChoice()
36
+ {
37
+ if ($this->_total > 0) {
38
+ arsort($this->_guesses);
39
+
40
+ foreach ($this->_guesses as $type => $votes) {
41
+ $confidence = ($votes / $this->_total) * 100;
42
+ if ($confidence >= self::CONFIDENCE_THRESHOLD) {
43
+ return $type;
44
+ }
45
+ break;
46
+ }
47
+ }
48
+
49
+ return self::DEFAULT_CHOICE;
50
+ }
51
+
52
+ /**
53
+ * @param type $name
54
+ * @param array $values
55
+ * @param bool $inversed
56
+ */
57
+ public function processValues(array $values = array(), $inversed = true)
58
+ {
59
+ $this->_guesses = $this->_defaultGuesses;
60
+
61
+ foreach ($values as $i => $value) {
62
+ $this->_total++;
63
+
64
+ if ($inversed) {
65
+ $this->processValue($i);
66
+ } else {
67
+ $this->processValue($value);
68
+ }
69
+
70
+ if ($this->_total === 1000) {
71
+ break;
72
+ }
73
+ }
74
+ }
75
+
76
+ /**
77
+ * @param text $name
78
+ * @param mixed $value
79
+ */
80
+ protected function processValue($value)
81
+ {
82
+ if ($value === '') {
83
+ return;
84
+ }
85
+
86
+ // Only A-Z
87
+ if (!is_int($value) && ctype_alpha($value)) {
88
+ $this->_guesses['text'] += 1;
89
+ return;
90
+ }
91
+
92
+ // Only 0-9
93
+ if (is_int($value) || ctype_digit($value)) {
94
+ if (strlen($value) <= 11) {
95
+ $this->_guesses['integer'] += 1;
96
+ } else {
97
+ $this->_guesses['text'] += 1;
98
+ $this->_guesses['integer'] = 0;
99
+ }
100
+ return;
101
+ }
102
+
103
+ // 0-9 with .
104
+ if (is_numeric($value)) {
105
+ if (strlen($value) <= 15) {
106
+ $this->_guesses['currency'] += 1;
107
+ } elseif (strlen($value) <= 53) {
108
+ $this->_guesses['float'] += 1;
109
+ $this->_guesses['currency'] = 0;
110
+ } else {
111
+ $this->_guesses['text'] += 1;
112
+ $this->_guesses['float'] = 0;
113
+ $this->_guesses['currency'] = 0;
114
+ }
115
+ return;
116
+ }
117
+
118
+ if (strtotime($value) !== false) {
119
+ // Possible date
120
+ $this->_guesses['date'] += 1;
121
+ } else {
122
+ // String is last choice
123
+ $this->_guesses['text'] += 1;
124
+ }
125
+ }
126
+ }
lib/Bronto/Api/List.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/maillistobject
6
+ *
7
+ * @method Bronto_Api_List_Row createRow() createRow(array $data = array())
8
+ */
9
+ class Bronto_Api_List extends Bronto_Api_Object
10
+ {
11
+ /**
12
+ * The object name.
13
+ *
14
+ * @var string
15
+ */
16
+ protected $_name = 'MailList';
17
+
18
+ /**
19
+ * @var array
20
+ */
21
+ protected $_methods = array(
22
+ 'addLists' => 'add',
23
+ 'readLists' => 'read',
24
+ 'updateLists' => 'update',
25
+ 'deleteLists' => 'delete',
26
+ 'addToList' => true,
27
+ 'clearLists' => true,
28
+ );
29
+
30
+ /**
31
+ * @param array $filter
32
+ * @param int $pageNumber
33
+ * @return Bronto_Api_Rowset
34
+ */
35
+ public function readAll(array $filter = array(), $pageNumber = 1)
36
+ {
37
+ $params = array();
38
+ $params['filter'] = $filter;
39
+ $params['pageNumber'] = (int) $pageNumber;
40
+ return $this->read($params);
41
+ }
42
+
43
+ /**
44
+ * @param array $data
45
+ * @return Bronto_Api_Rowset
46
+ */
47
+ public function clear(array $data = array())
48
+ {
49
+ if (array_values($data) !== $data) {
50
+ $data = array($data);
51
+ }
52
+ return $this->doRequest('clearLists', $data);
53
+ }
54
+ }
lib/Bronto/Api/List/Exception.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_List_Exception extends Bronto_Api_Exception
4
+ {
5
+ const INVALID_LIST = 501;
6
+ const ALREADY_EXISTS = 502;
7
+ const LIST_IS_SEGMENTED = 503;
8
+ const LIST_HAS_AUTOMATORS = 504;
9
+ const LIST_HAS_DELIVERIES = 505;
10
+ const ALREADY_ON_LIST = 506;
11
+ const MAX_CONTACTS_EXCEEDED = 507;
12
+ const NO_CONTACTS_SPECIFIED = 508;
13
+ const LABEL_LENGTH_EXCEEDED = 509;
14
+ const NAME_LENGTH_EXCEEDED = 510;
15
+ }
lib/Bronto/Api/List/Row.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @property-read string $id
5
+ * @property string $name
6
+ * @property string $label
7
+ * @property int $activeCount
8
+ * @property string $status
9
+ * @property string $visibility
10
+ * @method Bronto_Api_List_Row delete() delete()
11
+ * @method Bronto_Api_List getApiObject() getApiObject()
12
+ */
13
+ class Bronto_Api_List_Row extends Bronto_Api_Row implements Bronto_Api_Delivery_Recipient
14
+ {
15
+ /**
16
+ * Retrieves contacts for current list
17
+ *
18
+ * @param bool $includeLists
19
+ * @param array $fields
20
+ * @param int $pageNumber
21
+ * @return Bronto_Api_Rowset
22
+ */
23
+ public function getContacts($includeLists = false, array $fields = array(), $pageNumber = 1)
24
+ {
25
+ $contactObject = $this->getApi()->getContactObject();
26
+ $filter = array('listId' => $this->id);
27
+ return $contactObject->readAll($filter, $fields, $includeLists, $pageNumber);
28
+ }
29
+
30
+ /**
31
+ * @return Bronto_Api_List_Row
32
+ */
33
+ public function read()
34
+ {
35
+ if ($this->id) {
36
+ $params = array('id' => $this->id);
37
+ } elseif ($this->name) {
38
+ $params = array(
39
+ 'name' => array(
40
+ 'value' => $this->name,
41
+ 'operator' => 'EqualTo',
42
+ )
43
+ );
44
+ }
45
+
46
+ parent::_read($params);
47
+ return $this;
48
+ }
49
+
50
+ /**
51
+ * @param bool $upsert
52
+ * @param bool $refresh
53
+ * @return Bronto_Api_List_Row
54
+ */
55
+ public function save($upsert = true, $refresh = false)
56
+ {
57
+ if (!$upsert) {
58
+ parent::_save(false, $refresh);
59
+ }
60
+
61
+ try {
62
+ parent::_save(true, $refresh);
63
+ } catch (Bronto_Api_List_Exception $e) {
64
+ if ($e->getCode() === Bronto_Api_List_Exception::ALREADY_EXISTS) {
65
+ $this->_refresh();
66
+ } else {
67
+ $this->getApi()->throwException($e);
68
+ }
69
+ }
70
+
71
+ return $this;
72
+ }
73
+
74
+ /**
75
+ * @return Bronto_Api_List_Row
76
+ */
77
+ public function clear()
78
+ {
79
+ $data = array();
80
+ if (!$this->id) {
81
+ $this->_refresh();
82
+ }
83
+
84
+ if ($this->id) {
85
+ $data = array('id' => $this->id);
86
+ } else {
87
+ $exceptionClass = $this->getApiObject()->getExceptionClass();
88
+ throw new $exceptionClass('Nothing to clear.');
89
+ }
90
+
91
+ $this->getApiObject()->clear($data);
92
+ return $this;
93
+ }
94
+
95
+ /**
96
+ * Required by Bronto_Api_Delivery_Recipient
97
+ *
98
+ * @return true
99
+ */
100
+ public function isList()
101
+ {
102
+ return true;
103
+ }
104
+
105
+ /**
106
+ * Required by Bronto_Api_Delivery_Recipient
107
+ *
108
+ * @return false
109
+ */
110
+ public function isContact()
111
+ {
112
+ return false;
113
+ }
114
+
115
+ /**
116
+ * Required by Bronto_Api_Delivery_Recipient
117
+ *
118
+ * @return false
119
+ */
120
+ public function isSegment()
121
+ {
122
+ return false;
123
+ }
124
+ }
lib/Bronto/Api/Login.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/accountobject
6
+ *
7
+ * @method Bronto_Api_Login_Row createRow() createRow(array $data)
8
+ */
9
+ class Bronto_Api_Login extends Bronto_Api_Object
10
+ {
11
+ /**
12
+ * @var array
13
+ */
14
+ protected $_methods = array(
15
+ 'addLogins' => 'add',
16
+ 'readLogins' => 'read',
17
+ 'updateLogins' => 'update',
18
+ 'deleteLogins' => 'delete',
19
+ );
20
+
21
+ /**
22
+ * @param array $filter
23
+ * @param int $pageNumber
24
+ * @return Bronto_Api_Rowset
25
+ */
26
+ public function readAll(array $filter = array(), $pageNumber = 1)
27
+ {
28
+ if (empty($filter)) {
29
+ $filter = array(
30
+ 'username' => array(
31
+ 'operator' => 'StartsWith',
32
+ 'value' => ''
33
+ ),
34
+ );
35
+ }
36
+
37
+ $params = array();
38
+ $params['filter'] = $filter;
39
+ $params['pageNumber'] = (int) $pageNumber;
40
+
41
+ return parent::read($params);
42
+ }
43
+ }
lib/Bronto/Api/Login/ContactInformation.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/contactinformation
6
+ */
7
+ class Bronto_Api_Login_ContactInformation
8
+ {
9
+ /**
10
+ * @var string
11
+ */
12
+ public $organization;
13
+
14
+ /**
15
+ * @var string
16
+ */
17
+ public $firstName;
18
+
19
+ /**
20
+ * @var string
21
+ */
22
+ public $lastName;
23
+
24
+ /**
25
+ * @var string
26
+ */
27
+ public $email;
28
+
29
+ /**
30
+ * @var string
31
+ */
32
+ public $phone;
33
+
34
+ /**
35
+ * @var string
36
+ */
37
+ public $address;
38
+
39
+ /**
40
+ * @var string
41
+ */
42
+ public $address2;
43
+
44
+ /**
45
+ * @var string
46
+ */
47
+ public $city;
48
+
49
+ /**
50
+ * @var string
51
+ */
52
+ public $state;
53
+
54
+ /**
55
+ * @var string
56
+ */
57
+ public $zip;
58
+
59
+ /**
60
+ * @var string
61
+ */
62
+ public $country;
63
+
64
+ /**
65
+ * @var string
66
+ */
67
+ public $notes;
68
+
69
+ /**
70
+ * @param stdClass $data
71
+ */
72
+ public function __construct($data = array())
73
+ {
74
+ $data = (array) $data;
75
+ foreach ($data as $key => $value) {
76
+ if (property_exists($this, $key)) {
77
+ $this->{$key} = $value;
78
+ }
79
+ }
80
+ }
81
+
82
+ /**
83
+ * @param string $name
84
+ * @param mixed $value
85
+ */
86
+ public function __set($name, $value)
87
+ {
88
+ throw new InvalidArgumentException('All properties of the ContactInformation are read-only (currently)');
89
+ }
90
+ }
lib/Bronto/Api/Login/Exception.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_Login_Exception extends Bronto_Api_Exception
4
+ {
5
+
6
+ }
lib/Bronto/Api/Login/Row.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @property string $username
5
+ * @property string $password
6
+ * @property stdClass $contactInformation
7
+ * @property bool $permissionAgencyAdmin
8
+ * @property bool $permissionAdmin
9
+ * @property bool $permissionApi
10
+ * @property bool $permissionUpgrade
11
+ * @property bool $permissionFatigueOverride
12
+ * @property bool $permissionMessageCompose
13
+ * @property bool $permissionMessageDelete
14
+ * @property bool $permissionAutomatorCompose
15
+ * @property bool $permissionListCreateSend
16
+ * @property bool $permissionListCreate
17
+ * @property bool $permissionSegmentCreate
18
+ * @property bool $permissionFieldCreate
19
+ * @property bool $permissionFieldReorder
20
+ * @property bool $permissionSubscriberCreate
21
+ * @property bool $permissionSubscriberView
22
+ * @method Bronto_Api_Login_Row read() read()
23
+ * @method Bronto_Api_Login_Row save() save()
24
+ * @method Bronto_Api_Login_Row delete() delete()
25
+ * @method Bronto_Api_Login getApiObject() getApiObject()
26
+ */
27
+ class Bronto_Api_Login_Row extends Bronto_Api_Row
28
+ {
29
+ /**
30
+ * @return Bronto_Api_Login_ContactInformation
31
+ */
32
+ public function getContactInformation()
33
+ {
34
+ return new Bronto_Api_Login_ContactInformation($this->contactInformation);
35
+ }
36
+ }
lib/Bronto/Api/Message.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/messageobject
6
+ *
7
+ * @method Bronto_Api_Message_Row createRow() createRow(array $data = array())
8
+ */
9
+ class Bronto_Api_Message extends Bronto_Api_Object
10
+ {
11
+ /**
12
+ * @var array
13
+ */
14
+ protected $_methods = array(
15
+ 'addMessages' => 'add',
16
+ 'readMessages' => 'read',
17
+ 'updateMessages' => 'update',
18
+ 'deleteMessages' => 'delete',
19
+ );
20
+
21
+ /**
22
+ * @param array $filter
23
+ * @param bool $includeContent
24
+ * @param int $pageNumber
25
+ * @return Bronto_Api_Rowset
26
+ */
27
+ public function readAll(array $filter = array(), $includeContent = false, $pageNumber = 1)
28
+ {
29
+ $params = array();
30
+ $params['filter'] = $filter;
31
+ $params['includeContent'] = (bool) $includeContent;
32
+ $params['pageNumber'] = (int) $pageNumber;
33
+ return $this->read($params);
34
+ }
35
+ }
lib/Bronto/Api/Message/Exception.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_Message_Exception extends Bronto_Api_Exception
4
+ {
5
+ const INVALID_FOLDER_ID = 601; // The folder id is invalid.
6
+ const INVALID_FOLDER_NAME = 602; // The folder name is invalid:
7
+ const INVALID_MESSAGEGROUP = 603; // The specified message is invalid.
8
+ const INVALID_AUTOMATOR = 604; // The specified automator is invalid.
9
+ const INVALID_SOURCE_TEMPLATE = 605; // Invalid message from template:
10
+ const INVALID_CONTENT = 606; // You must specify message content
11
+ const INVALID_TYPE = 607; // Message content type must be either 'text' or 'html'.
12
+ const INVALID_SUBJECT = 608; // You must specify a message subject.
13
+ const INVALID_DYNAMIC_CONTENT = 609; // The message's dynamic content is invalid.
14
+ const INVALID_AUTOMATOR_NAME = 610; // The message rule name is invalid.
15
+ const INVALID_AUTOMATOR_TYPE = 611; // The message rule type is invalid.
16
+ const INVALID_AUTOMATOR_STATUS = 612; // The message rule status is invalid.
17
+ const AUTOMATOR_EXISTS = 613; // A message rule with this name already exists:
18
+ const FOLDER_EXISTS = 614; // A folder with this name already exists:
19
+ const MESSAGE_EXISTS = 615; // A message with this name already exists:
20
+ }
lib/Bronto/Api/Message/Row.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @property-read string $id
5
+ * @property string $name
6
+ * @property string $status
7
+ * @property string $messageFolderId
8
+ * @property array $content
9
+ * @method Bronto_Api_Message_Row delete() delete()
10
+ * @method Bronto_Api_Message getApiObject() getApiObject()
11
+ */
12
+ class Bronto_Api_Message_Row extends Bronto_Api_Row
13
+ {
14
+ /**
15
+ * @param Bronto_Api_DeliveryGroup_Row|string $deliveryGroup
16
+ * @return bool
17
+ */
18
+ public function addToDeliveryGroup($deliveryGroup)
19
+ {
20
+ if (!$this->id) {
21
+ $exceptionClass = $this->getExceptionClass();
22
+ throw new $exceptionClass("This Message has not been saved yet (has no MessageId)");
23
+ }
24
+
25
+ $deliveryGroupId = $deliveryGroup;
26
+ if ($deliveryGroup instanceOf Bronto_Api_DeliveryGroup_Row) {
27
+ if (!$deliveryGroup->id) {
28
+ $deliveryGroup = $deliveryGroup->read();
29
+ }
30
+ $deliveryGroupId = $deliveryGroup->id;
31
+ }
32
+
33
+ $deliveryGroupObject = $this->getApi()->getDeliveryGroupObject();
34
+ return $deliveryGroupObject->addToDeliveryGroup($deliveryGroupId, array(), array($this->id));
35
+ }
36
+
37
+ /**
38
+ * @return Bronto_Api_Message_Row
39
+ */
40
+ public function read()
41
+ {
42
+ if ($this->id) {
43
+ $params = array('id' => $this->id);
44
+ } elseif ($this->name) {
45
+ $params = array(
46
+ 'name' => array(
47
+ 'value' => $this->name,
48
+ 'operator' => 'EqualTo',
49
+ )
50
+ );
51
+ }
52
+
53
+ parent::_read($params);
54
+ return $this;
55
+ }
56
+
57
+ /**
58
+ * @param bool $upsert
59
+ * @param bool $refresh
60
+ * @return Bronto_Api_Message_Row
61
+ */
62
+ public function save($upsert = true, $refresh = false)
63
+ {
64
+ if (!$upsert) {
65
+ parent::_save(false, $refresh);
66
+ }
67
+
68
+ try {
69
+ parent::_save(true, $refresh);
70
+ } catch (Bronto_Api_Message_Exception $e) {
71
+ if ($e->getCode() === Bronto_Api_Message_Exception::MESSAGE_EXISTS) {
72
+ $this->_refresh();
73
+ } else {
74
+ $this->getApi()->throwException($e);
75
+ }
76
+ }
77
+
78
+ return $this;
79
+ }
80
+ }
lib/Bronto/Api/MessageRule.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/messageruleobject
6
+ *
7
+ * @method Bronto_Api_MessageRule_Row createRow() createRow(array $data = array())
8
+ */
9
+ class Bronto_Api_MessageRule extends Bronto_Api_Object
10
+ {
11
+ /**
12
+ * The object name.
13
+ *
14
+ * @var string
15
+ */
16
+ protected $_name = 'MessageRule';
17
+
18
+ /**
19
+ * @var array
20
+ */
21
+ protected $_methods = array(
22
+ 'addMessageRules' => 'add',
23
+ 'readMessageRules' => 'read',
24
+ 'updateMessageRules' => 'update',
25
+ 'deleteMessageRules' => 'delete',
26
+ );
27
+
28
+ /**
29
+ * @param array $filter
30
+ * @param int $pageNumber
31
+ * @return Bronto_Api_Rowset
32
+ */
33
+ public function readAll(array $filter = array(), $pageNumber = 1)
34
+ {
35
+ $params = array();
36
+ $params['filter'] = $filter;
37
+ $params['pageNumber'] = (int) $pageNumber;
38
+ return $this->read($params);
39
+ }
40
+ }
lib/Bronto/Api/MessageRule/Exception.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_MessageRule_Exception extends Bronto_Api_Exception
4
+ {
5
+ const INVALID_AUTOMATOR = 604; // The specified automator is invalid.
6
+ const INVALID_AUTOMATOR_NAME = 610; // The message rule name is invalid.
7
+ const INVALID_AUTOMATOR_TYPE = 611; // The message rule type is invalid.
8
+ const INVALID_AUTOMATOR_STATUS = 612; // The message rule status is invalid.
9
+ const AUTOMATOR_EXISTS = 613; // A message rule with this name already exists: %s
10
+ }
lib/Bronto/Api/MessageRule/Row.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @property-read id
5
+ * @property name
6
+ * @property type
7
+ * @property messagedId
8
+ * @method Bronto_Api_MessageRule_Row delete() delete()
9
+ * @method Bronto_Api_MessageRule getApiObject() getApiObject()
10
+ */
11
+ class Bronto_Api_MessageRule_Row extends Bronto_Api_Row
12
+ {
13
+ /**
14
+ * @param bool $returnData
15
+ * @return Bronto_Api_MessageRule_Row
16
+ */
17
+ public function read()
18
+ {
19
+ if ($this->id) {
20
+ $params = array('id' => $this->id);
21
+ } else {
22
+ $params = array(
23
+ 'name' => array(
24
+ 'value' => $this->name,
25
+ 'operator' => 'EqualTo',
26
+ )
27
+ );
28
+ }
29
+
30
+ return parent::_read($params, $returnData);
31
+ }
32
+
33
+ /**
34
+ * @param bool $upsert
35
+ * @param bool $refresh
36
+ * @return Bronto_Api_MessageRule_Row
37
+ */
38
+ public function save($upsert = true, $refresh = false)
39
+ {
40
+ if (!$upsert) {
41
+ parent::_save(false, $refresh);
42
+ }
43
+
44
+ try {
45
+ parent::_save(true, $refresh);
46
+ } catch (Bronto_Api_MessageRule_Exception $e) {
47
+ if ($e->getCode() === Bronto_Api_MessageRule_Exception::AUTOMATOR_EXISTS) {
48
+ $this->_refresh();
49
+ } else {
50
+ $this->getApi()->throwException($e);
51
+ }
52
+ }
53
+
54
+ return $this;
55
+ }
56
+ }
lib/Bronto/Api/Object.php ADDED
@@ -0,0 +1,580 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ *
6
+ * @method Bronto_Api_Rowset add() add(array $data)
7
+ * @method Bronto_Api_Rowset addOrUpdate() addOrUpdate(array $data)
8
+ * @method Bronto_Api_Rowset update() update(array $data)
9
+ * @method Bronto_Api_Rowset delete() delete(array $data)
10
+ * @method Bronto_Api_Rowset read() read(array $data)
11
+ */
12
+ abstract class Bronto_Api_Object
13
+ {
14
+ /** filterType */
15
+ const TYPE_AND = 'AND';
16
+ const TYPE_OR = 'OR';
17
+
18
+ /** filterOperator */
19
+ const OPER_EQ = 'EqualTo';
20
+ const OPER_NE = 'NotEqualTo';
21
+ const OPER_GT = 'GreaterThan';
22
+ const OPER_LT = 'LessThan';
23
+ const OPER_GE = 'GreaterThanEqualTo';
24
+ const OPER_LE = 'LessThanEqualTo';
25
+ const OPER_CONTAINS = 'Contains';
26
+ const OPER_NOT_CONTAINS = 'DoesNotContain';
27
+ const OPER_STARTS_WITH = 'StartsWith';
28
+ const OPER_ENDS_WITH = 'EndsWith';
29
+ const OPER_NOT_STARTS_WITH = 'DoesNotStartWith';
30
+ const OPER_NOT_ENDS_WITH = 'DoesNotEndWith';
31
+ const OPER_SAME_YEAR = 'SameYear';
32
+ const OPER_NOT_SAME_YEAR = 'NotSameYear';
33
+ const OPER_SAME_DAY = 'SameDay';
34
+ const OPER_NOT_SAME_DAY = 'NotSameDay';
35
+ const OPER_BEFORE = 'Before';
36
+ const OPER_AFTER = 'After';
37
+ const OPER_BEFORE_SAME = 'BeforeOrSameDay';
38
+ const OPER_AFTER_SAME = 'AfterOrSameDay';
39
+
40
+ /** readDirection */
41
+ const DIRECTION_FIRST = 'FIRST';
42
+ const DIRECTION_NEXT = 'NEXT';
43
+
44
+ /**
45
+ * Bronto_Api object
46
+ *
47
+ * @var Bronto_Api
48
+ */
49
+ protected $_api;
50
+
51
+ /**
52
+ * Various options for this object
53
+ *
54
+ * @var array
55
+ */
56
+ protected $_options = array();
57
+
58
+ /**
59
+ * API Methods this object supports
60
+ *
61
+ * @var array
62
+ */
63
+ protected $_methods = array();
64
+
65
+ /**
66
+ * @var array
67
+ */
68
+ protected $_methodsByType = array();
69
+
70
+ /**
71
+ * The object name
72
+ *
73
+ * @var string
74
+ */
75
+ protected $_name;
76
+
77
+ /**
78
+ * The primary key column or columns.
79
+ * A compound key should be declared as an array.
80
+ * You may declare a single-column primary key
81
+ * as a string.
82
+ *
83
+ * @var mixed
84
+ */
85
+ protected $_primary;
86
+
87
+ /**
88
+ * Classname for row
89
+ *
90
+ * @var string
91
+ */
92
+ protected $_rowClass;
93
+
94
+ /**
95
+ * Classname for rowset
96
+ *
97
+ * @var string
98
+ */
99
+ protected $_rowsetClass;
100
+
101
+ /**
102
+ * Classname for exceptions
103
+ *
104
+ * @var string
105
+ */
106
+ protected $_exceptionClass;
107
+
108
+ /**
109
+ * @var string
110
+ */
111
+ protected $_defaultRowClass = 'Bronto_Api_Row';
112
+
113
+ /**
114
+ * @var string
115
+ */
116
+ protected $_defaultRowsetClass = 'Bronto_Api_Rowset';
117
+
118
+ /**
119
+ * @var string
120
+ */
121
+ protected $_defaultExceptionClass = 'Bronto_Api_Exception';
122
+
123
+ /**
124
+ * How to iterate this object (page/date)
125
+ *
126
+ * @var int
127
+ */
128
+ protected $_iteratorType = Bronto_Api_Rowset_Iterator::TYPE_PAGE;
129
+
130
+ /**
131
+ * The key(s) to use when paginating
132
+ *
133
+ * @var array
134
+ */
135
+ protected $_iteratorParams = array(
136
+ 'pageNumber' => false,
137
+ );
138
+
139
+ /**
140
+ * Stored last request method
141
+ *
142
+ * @var string
143
+ */
144
+ protected $_lastRequestMethod;
145
+
146
+ /**
147
+ * Stored last request data
148
+ *
149
+ * @var array
150
+ */
151
+ protected $_lastRequestData;
152
+
153
+ /**
154
+ * @var array
155
+ */
156
+ protected $_writeCache = array(
157
+ 'add' => array(),
158
+ 'update' => array(),
159
+ 'addOrUpdate' => array(),
160
+ );
161
+
162
+ /**
163
+ * Constructor
164
+ *
165
+ * @param mixed $config
166
+ * @return void
167
+ */
168
+ public function __construct($config = array())
169
+ {
170
+ if (isset($config['api']) && $config['api'] instanceof Bronto_Api) {
171
+ $this->_api = $config['api'];
172
+ }
173
+
174
+ foreach ($this->_methods as $method => $type) {
175
+ if (is_string($type)) {
176
+ $this->_methodsByType[$type] = $method;
177
+ }
178
+ }
179
+
180
+ if (isset($this->_methodsByType['addOrUpdate'])) {
181
+ unset($this->_writeCache['add']);
182
+ unset($this->_writeCache['update']);
183
+ } else {
184
+ unset($this->_writeCache['addOrUpdate']);
185
+ }
186
+
187
+ $this->init();
188
+ }
189
+
190
+ /**
191
+ * Initialize object
192
+ *
193
+ * Called from {@link __construct()} as final step of object instantiation.
194
+ *
195
+ * @return void
196
+ */
197
+ public function init()
198
+ {
199
+ }
200
+
201
+ /**
202
+ * @param array $data
203
+ * @return Bronto_Api_Row
204
+ */
205
+ public function createRow(array $data = array())
206
+ {
207
+ $config = array(
208
+ 'apiObject' => $this,
209
+ 'data' => $data,
210
+ 'readOnly' => false,
211
+ 'stored' => false
212
+ );
213
+
214
+ $rowClass = $this->getRowClass();
215
+ return new $rowClass($config);
216
+ }
217
+
218
+ /**
219
+ * @param string $type
220
+ * @param array $data
221
+ * @param mixed $index
222
+ * @return Bronto_Api_Object
223
+ */
224
+ public function addToWriteCache($type, array $data, $index = false)
225
+ {
226
+ if ($index) {
227
+ $this->_writeCache[$type][$index] = $data;
228
+ } else {
229
+ $this->_writeCache[$type][] = $data;
230
+ }
231
+ return $this;
232
+ }
233
+
234
+ /**
235
+ * @return array
236
+ */
237
+ public function getWriteCache()
238
+ {
239
+ return $this->_writeCache;
240
+ }
241
+
242
+ /**
243
+ * @return int
244
+ */
245
+ public function getWriteCacheSize()
246
+ {
247
+ $total = 0;
248
+ foreach ($this->_writeCache as $type => $data) {
249
+ $total += count($this->_writeCache[$type]);
250
+ }
251
+ return $total;
252
+ }
253
+
254
+ /**
255
+ * Flush the write cache
256
+ * @return Bronto_Api_Rowset|array
257
+ */
258
+ public function flush()
259
+ {
260
+ $result = array();
261
+ foreach ($this->_writeCache as $type => $data) {
262
+ if (!empty($data)) {
263
+ $result[$type] = $this->{$type}(array_values($data));
264
+ $this->_writeCache[$type] = array();
265
+ }
266
+ }
267
+ return count($result) === 1 ? reset($result) : $result;
268
+ }
269
+
270
+ /**
271
+ * @param string $name
272
+ * @param array $arguments
273
+ * @return Bronto_Api_Rowset
274
+ */
275
+ public function __call($name, $arguments)
276
+ {
277
+ switch ($name) {
278
+ case 'add':
279
+ case 'update':
280
+ case 'delete':
281
+ case 'addOrUpdate':
282
+ $data = $arguments[0];
283
+ $method = $this->_methodsByType[$name];
284
+ if (array_values($data) !== $data) {
285
+ $data = array($data);
286
+ }
287
+ return $this->doRequest($method, $data, true);
288
+ break;
289
+ case 'read':
290
+ $data = $arguments[0];
291
+ $method = $this->_methodsByType[$name];
292
+ return $this->doRequest($method, $data, false);
293
+ break;
294
+ }
295
+
296
+ throw new BadMethodCallException("The method {$name} does not exist");
297
+ }
298
+
299
+ /**
300
+ * @param string $method
301
+ * @param array $data
302
+ */
303
+ protected function _beforeRequest($method, array $data = array())
304
+ {
305
+ if (!isset($this->_methods[$method])) {
306
+ $exceptionClass = $this->getExceptionClass();
307
+ throw new $exceptionClass("Method '{$method}' not allowed on " . $this->getName());
308
+ }
309
+ }
310
+
311
+ /**
312
+ * @param string $method
313
+ * @param array $data
314
+ * @param bool $canUseRetryer
315
+ * @return Bronto_Api_Rowset
316
+ */
317
+ public function doRequest($method, array $data, $canUseRetryer = false)
318
+ {
319
+ $this->_beforeRequest($method, $data);
320
+
321
+ $maxTries = (int) $this->getApi()->getOption('retry_limit', 5);
322
+ $tries = 0;
323
+ $success = false;
324
+
325
+ // Handle [frequent] API failures
326
+ do {
327
+ $tries++;
328
+ $error = false;
329
+
330
+ try {
331
+ // Store this request in case we need to retry later
332
+ $this->_lastRequestMethod = $method;
333
+ $this->_lastRequestData = $data;
334
+
335
+ // Attempt
336
+ $client = $this->getApi()->getSoapClient();
337
+ $result = $client->$method($data);
338
+ } catch (Exception $e) {
339
+ $error = true;
340
+ $exceptionClass = $this->getExceptionClass();
341
+ $exception = new $exceptionClass($e->getMessage(), $e->getCode(), $tries, $e);
342
+ if (!$exception->isRecoverable() || $tries === $maxTries) {
343
+ if ($canUseRetryer && $exception->isRecoverable()) {
344
+ if ($retryer = $this->getApi()->getRetryer()) {
345
+ $retryer->store($this);
346
+ }
347
+ }
348
+ return $this->getApi()->throwException($exception);
349
+ } else {
350
+ // Attempt to get a new session token
351
+ sleep(5);
352
+ $this->getApi()->login();
353
+ // If using readDirection, we have to start over
354
+ if (isset($data['filter']['readDirection'])) {
355
+ $data['filter']['readDirection'] = self::DIRECTION_FIRST;
356
+ }
357
+ }
358
+ }
359
+
360
+ if (!$error) {
361
+ $success = true;
362
+ }
363
+
364
+ } while (!$success && $tries <= $maxTries);
365
+
366
+ $result = isset($result->return) ? (array) $result->return : array();
367
+ return $this->_parseResponse($result, $data);
368
+ }
369
+
370
+ /**
371
+ * @param array $result
372
+ * @param array $params
373
+ * @return Bronto_Api_Rowset
374
+ */
375
+ public function _parseResponse(array $result, array $params = array())
376
+ {
377
+ $data = array();
378
+ if (isset($result['results'])) {
379
+ $data = (array) $result['results'];
380
+ } else {
381
+ if (isset($result[0])) {
382
+ $data = $result;
383
+ }
384
+ }
385
+
386
+ $config = array(
387
+ 'apiObject' => $this,
388
+ 'rowClass' => $this->getRowClass(),
389
+ 'data' => $data,
390
+ 'errors' => isset($result['errors']) ? (array) $result['errors'] : array(),
391
+ 'stored' => true,
392
+ 'params' => $params,
393
+ );
394
+
395
+ $rowsetClass = $this->getRowsetClass();
396
+ return new $rowsetClass($config);
397
+ }
398
+
399
+ /**
400
+ * @param Bronto_Api $api
401
+ * @return Bronto_Api_Object
402
+ */
403
+ public function setApi(Bronto_Api $api)
404
+ {
405
+ $this->_api = $api;
406
+ return $this;
407
+ }
408
+
409
+ /**
410
+ * @return Bronto_Api
411
+ */
412
+ public function getApi()
413
+ {
414
+ return $this->_api;
415
+ }
416
+
417
+ /**
418
+ * @return string
419
+ */
420
+ public function getName()
421
+ {
422
+ if ($this->_name === null) {
423
+ $className = get_class($this);
424
+ $this->_name = str_replace('Bronto_Api_', '', $className);
425
+ }
426
+
427
+ return $this->_name;
428
+ }
429
+
430
+ /**
431
+ * @return string
432
+ */
433
+ public function getRowClass()
434
+ {
435
+ if ($this->_rowClass === null) {
436
+ $className = get_class($this);
437
+ $rowClass = "{$className}_Row";
438
+ if (class_exists($rowClass)) {
439
+ $this->_rowClass = $rowClass;
440
+ } else {
441
+ $this->_rowClass = $this->_defaultRowClass;
442
+ }
443
+ }
444
+
445
+ return $this->_rowClass;
446
+ }
447
+
448
+ /**
449
+ * @return string
450
+ */
451
+ public function getRowsetClass()
452
+ {
453
+ if ($this->_rowsetClass === null) {
454
+ $className = get_class($this);
455
+ $rowsetClass = "{$className}_Rowset";
456
+ if (class_exists($rowsetClass, false)) {
457
+ $this->_rowsetClass = $rowsetClass;
458
+ } else {
459
+ $this->_rowsetClass = $this->_defaultRowsetClass;
460
+ }
461
+ }
462
+
463
+ return $this->_rowsetClass;
464
+ }
465
+
466
+ /**
467
+ * @return string
468
+ */
469
+ public function getExceptionClass()
470
+ {
471
+ if ($this->_exceptionClass === null) {
472
+ $className = get_class($this);
473
+ $exceptionClass = "{$className}_Exception";
474
+ if (class_exists($exceptionClass)) {
475
+ $this->_exceptionClass = $exceptionClass;
476
+ } else {
477
+ $this->_exceptionClass = $this->_defaultExceptionClass;
478
+ }
479
+ }
480
+
481
+ return $this->_exceptionClass;
482
+ }
483
+
484
+ /**
485
+ * @param string $key
486
+ * @return array|boolean
487
+ */
488
+ public function getOptionValues($key)
489
+ {
490
+ if (isset($this->_options[$key])) {
491
+ return $this->_options[$key];
492
+ }
493
+
494
+ return false;
495
+ }
496
+
497
+ /**
498
+ * @param string $key
499
+ * @param string $value
500
+ * @return boolean
501
+ */
502
+ public function isValidOptionValue($key, $value)
503
+ {
504
+ if ($values = $this->getOptionValues($key)) {
505
+ return in_array($value, $values);
506
+ }
507
+
508
+ return true;
509
+ }
510
+
511
+ /**
512
+ * @return int
513
+ */
514
+ public function getIteratorType()
515
+ {
516
+ return $this->_iteratorType;
517
+ }
518
+
519
+ /**
520
+ * @return array
521
+ */
522
+ public function getIteratorParams()
523
+ {
524
+ return $this->_iteratorParams;
525
+ }
526
+
527
+ /**
528
+ * @return bool
529
+ */
530
+ public function canIterate()
531
+ {
532
+ return $this->_iteratorType != Bronto_Api_Rowset_Iterator::TYPE_NONE;
533
+ }
534
+
535
+ /**
536
+ * @param string $method
537
+ * @return bool
538
+ */
539
+ public function hasMethod($method)
540
+ {
541
+ return isset($this->_methods[$method]);
542
+ }
543
+
544
+ /**
545
+ * @param string $type
546
+ * @return bool
547
+ */
548
+ public function hasMethodType($type)
549
+ {
550
+ return isset($this->_methodsByType[$type]);
551
+ }
552
+
553
+ /**
554
+ * @return string
555
+ */
556
+ public function getLastRequestMethod()
557
+ {
558
+ return $this->_lastRequestMethod;
559
+ }
560
+
561
+ /**
562
+ * @return array
563
+ */
564
+ public function getLastRequestData()
565
+ {
566
+ return $this->_lastRequestData;
567
+ }
568
+
569
+ /**
570
+ * @return array
571
+ */
572
+ public function __sleep()
573
+ {
574
+ return array(
575
+ '_api',
576
+ '_lastRequestMethod',
577
+ '_lastRequestData',
578
+ );
579
+ }
580
+ }
lib/Bronto/Api/Order.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/orderobject
6
+ *
7
+ * @method Bronto_Api_Order_Row createRow() createRow(array $data = array())
8
+ */
9
+ class Bronto_Api_Order extends Bronto_Api_Object
10
+ {
11
+ /**
12
+ * @var array
13
+ */
14
+ protected $_methods = array(
15
+ 'addOrUpdateOrders' => 'addOrUpdate',
16
+ 'deleteOrders' => 'delete',
17
+ );
18
+ }
lib/Bronto/Api/Order/Exception.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_Order_Exception extends Bronto_Api_Exception
4
+ {
5
+
6
+ }
lib/Bronto/Api/Order/Product.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ */
6
+ class Bronto_Api_Order_Product
7
+ {
8
+ /**
9
+ * @var string
10
+ */
11
+ public $id;
12
+
13
+ /**
14
+ * @var string
15
+ */
16
+ public $sku;
17
+
18
+ /**
19
+ * @var string
20
+ */
21
+ public $name;
22
+
23
+ /**
24
+ * @var string
25
+ */
26
+ public $description;
27
+
28
+ /**
29
+ * @var string
30
+ */
31
+ public $category;
32
+
33
+ /**
34
+ * @var string
35
+ */
36
+ public $image;
37
+
38
+ /**
39
+ * @var string
40
+ */
41
+ public $url;
42
+
43
+ /**
44
+ * @var int
45
+ */
46
+ public $quantity;
47
+
48
+ /**
49
+ * @var float
50
+ */
51
+ public $price;
52
+
53
+ /**
54
+ * @param array $data
55
+ */
56
+ public function __construct($data = array())
57
+ {
58
+ $data = (array) $data;
59
+ foreach ($data as $key => $value) {
60
+ if (property_exists($this, $key)) {
61
+ $this->{$key} = $value;
62
+ }
63
+ }
64
+ }
65
+ }
lib/Bronto/Api/Order/Row.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @property-read string $id
5
+ * @property string $contactId
6
+ * @property string $email
7
+ * @property array $products
8
+ * @property string $orderDate
9
+ * @property string $deliveryId
10
+ * @property string $messageId
11
+ * @property string $automatorId
12
+ * @property string $listId
13
+ * @property string $segmentId
14
+ * @property string $deliveryType
15
+ * @property-write string $tid
16
+ * @method Bronto_Api_Order_Row delete() delete()
17
+ * @method Bronto_Api_Order getApiObject() getApiObject()
18
+ */
19
+ class Bronto_Api_Order_Row extends Bronto_Api_Row
20
+ {
21
+ /**
22
+ * @param bool $upsert Ignored
23
+ * @param bool $refresh
24
+ * @return Bronto_Api_Order_Row
25
+ */
26
+ public function save($upsert = true, $refresh = false)
27
+ {
28
+ parent::_add(true);
29
+ return $this;
30
+ }
31
+
32
+ /**
33
+ * @return Bronto_Api_Order_Row
34
+ */
35
+ public function persist()
36
+ {
37
+ return parent::_persist('addOrUpdate', false);
38
+ }
39
+
40
+ /**
41
+ * Set row field value
42
+ *
43
+ * @param string $columnName The column key.
44
+ * @param mixed $value The value for the property.
45
+ */
46
+ public function __set($columnName, $value)
47
+ {
48
+ switch (strtolower($columnName)) {
49
+ case 'email':
50
+ // Trim whitespace
51
+ $value = preg_replace('/\s+/', '', $value);
52
+ // Check if email got truncated
53
+ if (substr($value, -1) === '.') {
54
+ $value .= 'com';
55
+ }
56
+ break;
57
+ }
58
+
59
+ return parent::__set($columnName, $value);
60
+ }
61
+
62
+ /**
63
+ * @param array $data
64
+ * @return Bronto_Api_Order_Product
65
+ */
66
+ public function addProduct(array $data = array())
67
+ {
68
+ $product = new Bronto_Api_Order_Product($data);
69
+ $productId = $product->id;
70
+
71
+ if (empty($productId)) {
72
+ throw new Bronto_Api_Order_Exception('Product must have a value for ID.');
73
+ }
74
+
75
+ if (isset($this->products[$productId])) {
76
+ throw new Bronto_Api_Order_Exception("Product already exists in Order with ID: {$productId}");
77
+ }
78
+
79
+ $this->products[$productId] = $product;
80
+ return $product;
81
+ }
82
+ }
lib/Bronto/Api/Row.php ADDED
@@ -0,0 +1,730 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ */
6
+ abstract class Bronto_Api_Row implements ArrayAccess, IteratorAggregate
7
+ {
8
+ /**
9
+ * The data for each column in the row (column_name => value).
10
+ * The keys must match the physical names of columns in the
11
+ * table for which this row is defined.
12
+ *
13
+ * @var array
14
+ */
15
+ protected $_data = array();
16
+
17
+ /**
18
+ * This is set to a copy of $_data when the data is fetched from
19
+ * the API, specified as a new tuple in the constructor, or
20
+ * when dirty data is posted to the database with save().
21
+ *
22
+ * @var array
23
+ */
24
+ protected $_cleanData = array();
25
+
26
+ /**
27
+ * Tracks columns where data has been updated. Allows more specific insert and
28
+ * update operations.
29
+ *
30
+ * @var array
31
+ */
32
+ protected $_modifiedFields = array();
33
+
34
+ /**
35
+ * Tracks columns that are dates.
36
+ *
37
+ * @var array
38
+ */
39
+ protected $_dateFields = array();
40
+
41
+ /**
42
+ * A row is marked read only if it contains columns that are not physically
43
+ * represented within the API schema. This can also be passed as a
44
+ * run-time config options as a means of protecting row data.
45
+ *
46
+ * @var boolean
47
+ */
48
+ protected $_readOnly = false;
49
+
50
+ /**
51
+ * Primary row key
52
+ *
53
+ * @var string
54
+ */
55
+ protected $_primary = 'id';
56
+
57
+ /**
58
+ * API Object
59
+ *
60
+ * @var Bronto_Api_Object
61
+ */
62
+ protected $_apiObject;
63
+
64
+ /**
65
+ * @var bool
66
+ */
67
+ protected $_isNew = false;
68
+
69
+ /**
70
+ * @var bool
71
+ */
72
+ protected $_isError = false;
73
+
74
+ /**
75
+ * @var int
76
+ */
77
+ protected $_errorCode;
78
+
79
+ /**
80
+ * @var string
81
+ */
82
+ protected $_errorString;
83
+
84
+ /**
85
+ * @var bool
86
+ */
87
+ protected $_isLoaded = true;
88
+
89
+ /**
90
+ * Constructor
91
+ *
92
+ * @param array $config
93
+ */
94
+ public function __construct(array $config = array())
95
+ {
96
+ if (isset($config['apiObject']) && $config['apiObject'] instanceof Bronto_Api_Object) {
97
+ $this->_apiObject = $config['apiObject'];
98
+ }
99
+
100
+ if (isset($config['data'])) {
101
+ if (!is_array($config['data'])) {
102
+ throw new Bronto_Api_Row_Exception('Data must be an array');
103
+ }
104
+ $this->setData($config['data']);
105
+ }
106
+
107
+ if (isset($config['stored']) && $config['stored'] === true) {
108
+ $this->_cleanData = $this->_data;
109
+ } else {
110
+ $this->_isLoaded = false;
111
+ $this->_cleanData = array();
112
+ foreach ($this->_data as $key => $value) {
113
+ $this->_modifiedFields[$key] = true;
114
+ }
115
+ }
116
+
117
+ if (isset($config['readOnly']) && $config['readOnly'] === true) {
118
+ $this->_readOnly = true;
119
+ }
120
+
121
+ $this->init();
122
+ }
123
+
124
+ /**
125
+ * @param array $data
126
+ * @return Bronto_Api_Row
127
+ */
128
+ public function setData(array $data = array())
129
+ {
130
+ if (isset($data['isNew'])) {
131
+ $this->_isNew = (bool) $data['isNew'];
132
+ $this->_isLoaded = true;
133
+ unset($data['isNew']);
134
+ }
135
+
136
+ if (isset($data['isError'])) {
137
+ $this->_isError = (bool) $data['isError'];
138
+ if ($this->_isError) {
139
+ $this->_readOnly = true;
140
+ $this->_isLoaded = false;
141
+ }
142
+ unset($data['isError']);
143
+ }
144
+
145
+ if (isset($data['errorCode'])) {
146
+ $this->_errorCode = (int) $data['errorCode'];
147
+ unset($data['errorCode']);
148
+ }
149
+
150
+ if (isset($data['errorString'])) {
151
+ $this->_errorString = (string) $data['errorString'];
152
+ unset($data['errorString']);
153
+ }
154
+
155
+ $this->_data = array_merge($this->_data, $data);
156
+ $this->_refresh(false);
157
+ $this->init();
158
+
159
+ return $this;
160
+ }
161
+
162
+ /**
163
+ * Initialize object
164
+ *
165
+ * Called from {@link __construct()} as final step of object instantiation.
166
+ *
167
+ * @return void
168
+ */
169
+ public function init()
170
+ {
171
+ }
172
+
173
+ /**
174
+ * Proxy to __isset
175
+ * Required by the ArrayAccess implementation
176
+ *
177
+ * @param string $offset
178
+ * @return boolean
179
+ */
180
+ public function offsetExists($offset)
181
+ {
182
+ return $this->__isset($offset);
183
+ }
184
+
185
+ /**
186
+ * Proxy to __get
187
+ * Required by the ArrayAccess implementation
188
+ *
189
+ * @param string $offset
190
+ * @return string
191
+ */
192
+ public function offsetGet($offset)
193
+ {
194
+ return $this->__get($offset);
195
+ }
196
+
197
+ /**
198
+ * Proxy to __set
199
+ * Required by the ArrayAccess implementation
200
+ *
201
+ * @param string $offset
202
+ * @param mixed $value
203
+ */
204
+ public function offsetSet($offset, $value)
205
+ {
206
+ $this->__set($offset, $value);
207
+ }
208
+
209
+ /**
210
+ * Proxy to __unset
211
+ * Required by the ArrayAccess implementation
212
+ *
213
+ * @param string $offset
214
+ */
215
+ public function offsetUnset($offset)
216
+ {
217
+ return $this->__unset($offset);
218
+ }
219
+
220
+ /**
221
+ * @return ArrayIterator
222
+ */
223
+ public function getIterator()
224
+ {
225
+ return new ArrayIterator((array) $this->_data);
226
+ }
227
+
228
+ /**
229
+ * Returns the column/value data as an array.
230
+ *
231
+ * @return array
232
+ */
233
+ public function toArray()
234
+ {
235
+ return (array) $this->_data;
236
+ }
237
+
238
+ /**
239
+ * @return array
240
+ */
241
+ public function __toArray()
242
+ {
243
+ return $this->toArray();
244
+ }
245
+
246
+ /**
247
+ * @return Bronto_Api_Row
248
+ */
249
+ public function persist()
250
+ {
251
+ if ($this->_readOnly === true) {
252
+ throw new Bronto_Api_Row_Exception(sprintf("Cannot persist a %s record.", $this->getApiObject()->getName()));
253
+ }
254
+
255
+ $type = false;
256
+ if ($this->getApiObject()->hasMethodType('addOrUpdate')) {
257
+ $type = 'addOrUpdate';
258
+ } else {
259
+ if (empty($this->_cleanData)) {
260
+ $type = 'add';
261
+ } else {
262
+ $type = 'update';
263
+ }
264
+ }
265
+
266
+ return $this->_persist($type);
267
+ }
268
+
269
+ /**
270
+ * @return Bronto_Api_Row
271
+ */
272
+ public function persistDelete()
273
+ {
274
+ if (!$this->getApiObject()->hasMethodType('delete')) {
275
+ $exceptionClass = $this->getApiObject()->getExceptionClass();
276
+ throw new $exceptionClass('Cannot delete a row of type: ' . $this->getApiObject()->getName());
277
+ }
278
+
279
+ return $this->_persist('delete');
280
+ }
281
+
282
+ /**
283
+ * Persist an object for write caching
284
+ *
285
+ * @param string $type
286
+ * @param mixed $defaultIndex
287
+ * @return Bronto_Api_Row
288
+ */
289
+ public function _persist($type, $defaultIndex = false)
290
+ {
291
+ $data = array_intersect_key($this->_data, $this->_modifiedFields);
292
+ $tempPrimaryKey = $this->_primary;
293
+ if (!empty($this->{$tempPrimaryKey})) {
294
+ $defaultIndex = $this->{$tempPrimaryKey};
295
+ if ($type === 'delete') {
296
+ $data = array($this->_primary => $this->{$tempPrimaryKey});
297
+ } else {
298
+ $data = array_merge(array($this->_primary => $this->{$tempPrimaryKey}), $data);
299
+ }
300
+ }
301
+
302
+ $this->getApiObject()->addToWriteCache($type, $data, $defaultIndex);
303
+ return $this;
304
+ }
305
+
306
+ /**
307
+ * @return Bronto_Api_Row
308
+ */
309
+ public function read()
310
+ {
311
+ $data = array();
312
+ if ($this->id) {
313
+ $data = array('id' => $this->id);
314
+ } else {
315
+ throw new Bronto_Api_Row_Exception('Trying to read Row without unique identifier for lookup');
316
+ }
317
+
318
+ $this->_read($data);
319
+ return $this;
320
+ }
321
+
322
+ /**
323
+ * @param bool $upsert
324
+ * @param bool $refresh
325
+ * @return Bronto_Api_Row
326
+ */
327
+ public function save($upsert = false, $refresh = false)
328
+ {
329
+ $this->_save($upsert, $refresh);
330
+ return $this;
331
+ }
332
+
333
+ /**
334
+ * @return Bronto_Api_Row
335
+ */
336
+ public function delete()
337
+ {
338
+ if (!$this->getApiObject()->hasMethodType('delete')) {
339
+ $exceptionClass = $this->getApiObject()->getExceptionClass();
340
+ throw new $exceptionClass('Cannot delete a row of type: ' . $this->getApiObject()->getName());
341
+ }
342
+
343
+ $data = array();
344
+ if (!$this->id) {
345
+ $this->_refresh();
346
+ }
347
+
348
+ if ($this->id) {
349
+ $data = array('id' => $this->id);
350
+ } else {
351
+ $exceptionClass = $this->getApiObject()->getExceptionClass();
352
+ throw new $exceptionClass('Trying to delete Row without unique identifier for lookup');
353
+ }
354
+
355
+ $this->_delete($data);
356
+ return $this;
357
+ }
358
+
359
+ /**
360
+ * Refreshes properties from the API.
361
+ * @param bool $pull
362
+ */
363
+ protected function _refresh($pull = true)
364
+ {
365
+ if ($pull) {
366
+ $this->read();
367
+ }
368
+ $this->_cleanData = $this->_data;
369
+ $this->_modifiedFields = array();
370
+ }
371
+
372
+ /**
373
+ * @param array $filter
374
+ */
375
+ protected function _read(array $filter = array())
376
+ {
377
+ if (empty($filter)) {
378
+ $exceptionClass = $this->getApiObject()->getExceptionClass();
379
+ throw new $exceptionClass('Trying to read Row without unique identifier for lookup');
380
+ }
381
+
382
+ /* @var $rowset Bronto_Api_Rowset */
383
+ $rowset = $this->getApiObject()->readAll($filter);
384
+
385
+ if ($rowset->hasErrors()) {
386
+ // Reset class
387
+ $error = $rowset->getError();
388
+ $this->_readOnly = true;
389
+ $this->_isLoaded = false;
390
+ $this->_isError = true;
391
+ $this->_errorCode = $error['code'];
392
+ $this->_errorString = $error['message'];
393
+
394
+ $exceptionClass = $this->getApiObject()->getExceptionClass();
395
+ throw new $exceptionClass($error['message'], $error['code']);
396
+ }
397
+
398
+ if ($rowset->count() > 0) {
399
+ // Reset all fields
400
+ $this->_isLoaded = true;
401
+ $this->_readOnly = false;
402
+ $this->_isError = false;
403
+ $this->_isNew = false;
404
+
405
+ $data = $rowset->offsetGetData(0);
406
+ $this->setData($data);
407
+ }
408
+ }
409
+
410
+ /**
411
+ * Saves the properties to the API.
412
+ *
413
+ * This performs an intelligent add/update, and can reload the
414
+ * properties with fresh data from the API on success.
415
+ *
416
+ * @param bool $upsert
417
+ * @param bool $refresh
418
+ */
419
+ protected function _save($upsert = true, $refresh = false)
420
+ {
421
+ /**
422
+ * If the _cleanData array is empty,
423
+ * this is an ADD of a new row.
424
+ * Otherwise it is an UPDATE.
425
+ */
426
+ if (empty($this->_cleanData)) {
427
+ if ($upsert) {
428
+ if ($this->getApiObject()->hasMethodType('addOrUpdate')) {
429
+ $this->_add(true);
430
+ } else {
431
+ $this->_add(false);
432
+ }
433
+ } else {
434
+ $this->_add(false);
435
+ }
436
+ } else {
437
+ $this->_update();
438
+ }
439
+
440
+ $refreshOnSave = $this->getApi()->getOption('refresh_on_save');
441
+ if ($refreshOnSave || $refresh) {
442
+ $this->_refresh();
443
+ }
444
+ }
445
+
446
+ /**
447
+ * @param bool $upsert
448
+ */
449
+ protected function _add($upsert = false)
450
+ {
451
+ if ($this->_readOnly === true) {
452
+ throw new Bronto_Api_Row_Exception(sprintf("Cannot create %s record.", $this->getApiObject()->getName()));
453
+ }
454
+
455
+ $data = array_intersect_key($this->_data, $this->_modifiedFields);
456
+ if ($upsert) {
457
+ $tempPrimaryKey = $this->_primary;
458
+ if (!empty($this->{$tempPrimaryKey})) {
459
+ $data = array_merge(array($this->_primary => $this->{$tempPrimaryKey}), $data);
460
+ }
461
+ $rowset = $this->getApiObject()->addOrUpdate(array($data));
462
+ } else {
463
+ $rowset = $this->getApiObject()->add(array($data));
464
+ }
465
+
466
+ if ($rowset->hasErrors()) {
467
+ // Reset class
468
+ $error = $rowset->getError();
469
+ $this->_readOnly = true;
470
+ $this->_isLoaded = false;
471
+ $this->_isError = true;
472
+ $this->_errorCode = $error['code'];
473
+ $this->_errorString = $error['message'];
474
+
475
+ $exceptionClass = $this->getApiObject()->getExceptionClass();
476
+ throw new $exceptionClass($error['message'], $error['code']);
477
+ }
478
+
479
+ if ($rowset->count() > 0) {
480
+ // Reset all fields
481
+ $this->_isLoaded = true;
482
+ $this->_readOnly = false;
483
+ $this->_isError = false;
484
+ $this->_isNew = false;
485
+
486
+ $data = $rowset->offsetGetData(0);
487
+ $this->setData($data);
488
+ }
489
+ }
490
+
491
+ protected function _update()
492
+ {
493
+ if ($this->_readOnly === true) {
494
+ throw new Bronto_Api_Row_Exception(sprintf("Cannot update %s record.", $this->getApiObject()->getName()));
495
+ }
496
+
497
+ $data = array_intersect_key($this->_data, $this->_modifiedFields);
498
+ if (count($data) > 0) {
499
+ $tempPrimaryKey = $this->_primary;
500
+ if (!empty($this->{$tempPrimaryKey})) {
501
+ $data = array_merge(array($this->_primary => $this->{$tempPrimaryKey}), $data);
502
+ }
503
+ $rowset = $this->getApiObject()->update(array($data));
504
+
505
+ if ($rowset->hasErrors()) {
506
+ // Reset class
507
+ $error = $rowset->getError();
508
+ $this->_readOnly = true;
509
+ $this->_isLoaded = false;
510
+ $this->_isError = true;
511
+ $this->_errorCode = $error['code'];
512
+ $this->_errorString = $error['message'];
513
+
514
+ $exceptionClass = $this->getApiObject()->getExceptionClass();
515
+ throw new $exceptionClass($error['message'], $error['code']);
516
+ }
517
+
518
+ if ($rowset->count() > 0) {
519
+ // Reset all fields
520
+ $this->_isLoaded = true;
521
+ $this->_readOnly = false;
522
+ $this->_isError = false;
523
+ $this->_isNew = false;
524
+
525
+ $data = $rowset->offsetGetData(0);
526
+ $this->setData($data);
527
+ }
528
+ }
529
+ }
530
+
531
+ /**
532
+ * @param array $data
533
+ */
534
+ protected function _delete(array $data)
535
+ {
536
+ if ($this->_readOnly === true) {
537
+ throw new Bronto_Api_Row_Exception(sprintf("Cannot delete this read-only %s record.", $this->getApiObject()->getName()));
538
+ }
539
+
540
+ $rowset = $this->getApiObject()->delete(array($data));
541
+
542
+ if ($rowset->hasErrors()) {
543
+ // Reset class
544
+ $error = $rowset->getError();
545
+ $this->_readOnly = true;
546
+ $this->_isLoaded = false;
547
+ $this->_isError = true;
548
+ $this->_errorCode = $error['code'];
549
+ $this->_errorString = $error['message'];
550
+
551
+ $exceptionClass = $this->getApiObject()->getExceptionClass();
552
+ throw new $exceptionClass($error['message'], $error['code']);
553
+ }
554
+
555
+ if ($rowset->count() > 0) {
556
+ // Reset all fields to indicate that the row is not there
557
+ $this->_data = array();
558
+ $this->_cleanData = array();
559
+ $this->_modifiedFields = array();
560
+ $this->_isLoaded = false;
561
+ $this->_readOnly = true;
562
+ $this->_isError = false;
563
+ $this->_isNew = false;
564
+
565
+ $data = $rowset->offsetGetData(0);
566
+ $this->setData($data);
567
+ }
568
+ }
569
+
570
+ /**
571
+ * Retrieve row field value
572
+ *
573
+ * @param string $columnName The user-specified column name.
574
+ * @return string The corresponding column value.
575
+ */
576
+ public function __get($columnName)
577
+ {
578
+ if (!array_key_exists($columnName, $this->_data)) {
579
+ return null;
580
+ }
581
+ return $this->_data[$columnName];
582
+ }
583
+
584
+ /**
585
+ * Set row field value
586
+ *
587
+ * @param string $columnName The column key.
588
+ * @param mixed $value The value for the property.
589
+ */
590
+ public function __set($columnName, $value)
591
+ {
592
+ if ($this->_readOnly === false) {
593
+ $this->_data[$columnName] = $value;
594
+ $this->_modifiedFields[$columnName] = true;
595
+ }
596
+ }
597
+
598
+ /**
599
+ * Unset row field value
600
+ *
601
+ * @param string $columnName The column key.
602
+ */
603
+ public function __unset($columnName)
604
+ {
605
+ if ($this->_readOnly === false) {
606
+ unset($this->_data[$columnName]);
607
+ }
608
+ }
609
+
610
+ /**
611
+ * Test existence of row field
612
+ *
613
+ * @param string $columnName The column key.
614
+ * @return bool
615
+ */
616
+ public function __isset($columnName)
617
+ {
618
+ return array_key_exists($columnName, $this->_data);
619
+ }
620
+
621
+ /**
622
+ * @param Bronto_Api_Object $apiObject
623
+ * @return Bronto_Api_Row
624
+ */
625
+ public function setApiObject(Bronto_Api_Object $apiObject)
626
+ {
627
+ $this->_apiObject = $apiObject;
628
+ return $this;
629
+ }
630
+
631
+ /**
632
+ * @return Bronto_Api_Object
633
+ */
634
+ public function getApiObject()
635
+ {
636
+ return $this->_apiObject;
637
+ }
638
+
639
+ /**
640
+ * @return Bronto_Api
641
+ */
642
+ public function getApi()
643
+ {
644
+ return $this->_apiObject->getApi();
645
+ }
646
+
647
+ /**
648
+ * Test the read-only status of the row.
649
+ *
650
+ * @return boolean
651
+ */
652
+ public function isReadOnly()
653
+ {
654
+ return $this->_readOnly;
655
+ }
656
+
657
+ /**
658
+ * Set the read-only status of the row.
659
+ *
660
+ * @param boolean $flag
661
+ * @return boolean
662
+ */
663
+ public function setReadOnly($flag)
664
+ {
665
+ $this->_readOnly = (bool) $flag;
666
+ }
667
+
668
+ /**
669
+ * @return array
670
+ */
671
+ public function getData()
672
+ {
673
+ return $this->_data;
674
+ }
675
+
676
+ /**
677
+ * @return array
678
+ */
679
+ public function getDateFields()
680
+ {
681
+ return $this->_dateFields;
682
+ }
683
+
684
+ /**
685
+ * @param string $key
686
+ * @return bool
687
+ */
688
+ public function isDateField($key)
689
+ {
690
+ return (bool) isset($this->_dateFields[$key]);
691
+ }
692
+
693
+ /**
694
+ * @return bool
695
+ */
696
+ public function isNew()
697
+ {
698
+ return (bool) $this->_isNew;
699
+ }
700
+
701
+ /**
702
+ * @return bool
703
+ */
704
+ public function hasError()
705
+ {
706
+ return (bool) $this->_isError;
707
+ }
708
+
709
+ /**
710
+ * @return int|bool
711
+ */
712
+ public function getErrorCode()
713
+ {
714
+ if ($this->hasError()) {
715
+ return $this->_errorCode;
716
+ }
717
+ return false;
718
+ }
719
+
720
+ /**
721
+ * @return int|bool
722
+ */
723
+ public function getErrorMessage()
724
+ {
725
+ if ($this->hasError()) {
726
+ return $this->_errorString;
727
+ }
728
+ return false;
729
+ }
730
+ }
lib/Bronto/Api/Row/Exception.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_Row_Exception extends Bronto_Api_Exception
4
+ {
5
+
6
+ }
lib/Bronto/Api/Rowset.php ADDED
@@ -0,0 +1,395 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ */
6
+ class Bronto_Api_Rowset implements SeekableIterator, Countable, ArrayAccess
7
+ {
8
+ /**
9
+ * The original data for each row.
10
+ *
11
+ * @var array
12
+ */
13
+ protected $_data = array();
14
+
15
+ /**
16
+ * Any errors for each row.
17
+ *
18
+ * @var array
19
+ */
20
+ protected $_errors = false;
21
+
22
+ /**
23
+ * API Object
24
+ *
25
+ * @var Bronto_Api_Object
26
+ */
27
+ protected $_apiObject;
28
+
29
+ /**
30
+ * API Object class name
31
+ *
32
+ * @var string
33
+ */
34
+ protected $_apiObjectClass;
35
+
36
+ /**
37
+ * Row class name
38
+ *
39
+ * @var string
40
+ */
41
+ protected $_rowClass = 'Bronto_Api_Row';
42
+
43
+ /**
44
+ * Iterator pointer.
45
+ *
46
+ * @var integer
47
+ */
48
+ protected $_pointer = 0;
49
+
50
+ /**
51
+ * How many data rows there are.
52
+ *
53
+ * @var integer
54
+ */
55
+ protected $_count;
56
+
57
+ /**
58
+ * Collection of instantiated Bronto_Api_Row objects.
59
+ *
60
+ * @var array
61
+ */
62
+ protected $_rows = array();
63
+
64
+ /**
65
+ * @var boolean
66
+ */
67
+ protected $_stored = false;
68
+
69
+ /**
70
+ * @var boolean
71
+ */
72
+ protected $_readOnly = false;
73
+
74
+ /**
75
+ * @var array
76
+ */
77
+ protected $_params = array();
78
+
79
+ /**
80
+ * Constructor.
81
+ *
82
+ * @param array $config
83
+ */
84
+ public function __construct(array $config)
85
+ {
86
+ if (isset($config['apiObject'])) {
87
+ $this->_apiObject = $config['apiObject'];
88
+ $this->_apiObjectClass = get_class($this->_apiObject);
89
+ }
90
+
91
+ if (isset($config['rowClass'])) {
92
+ $this->_rowClass = (string) $config['rowClass'];
93
+ }
94
+
95
+ if (isset($config['data'])) {
96
+ $this->_data = (array) $config['data'];
97
+ foreach ($this->_data as $key => $value) {
98
+ $this->_data[$key] = (array) $value;
99
+ }
100
+ }
101
+
102
+ if (isset($config['errors'])) {
103
+ $this->_errors = (array) $config['errors'];
104
+ }
105
+
106
+ if (isset($config['readOnly'])) {
107
+ $this->_readOnly = (bool) $config['readOnly'];
108
+ }
109
+
110
+ if (isset($config['stored'])) {
111
+ $this->_stored = (bool) $config['stored'];
112
+ }
113
+
114
+ if (isset($config['params'])) {
115
+ $this->_params = $config['params'];
116
+ }
117
+
118
+ // Set the count of rows
119
+ $this->_count = count($this->_data);
120
+ $this->init();
121
+ }
122
+
123
+ /**
124
+ * Initialize object
125
+ *
126
+ * Called from {@link __construct()} as final step of object instantiation.
127
+ *
128
+ * @return void
129
+ */
130
+ public function init()
131
+ {
132
+ }
133
+
134
+ /**
135
+ * @return Bronto_Api_Object
136
+ */
137
+ public function getApiObject()
138
+ {
139
+ return $this->_apiObject;
140
+ }
141
+
142
+ /**
143
+ * @return string
144
+ */
145
+ public function getApiObjectClass()
146
+ {
147
+ return $this->_apiObjectClass;
148
+ }
149
+
150
+ /**
151
+ * @return array
152
+ */
153
+ public function getParams()
154
+ {
155
+ return $this->_params;
156
+ }
157
+
158
+ /**
159
+ * Rewind the Iterator to the first element.
160
+ * Similar to the reset() function for arrays in PHP.
161
+ * Required by interface Iterator.
162
+ *
163
+ * @return Bronto_Api_Rowset Fluent interface.
164
+ */
165
+ public function rewind()
166
+ {
167
+ $this->_pointer = 0;
168
+ return $this;
169
+ }
170
+
171
+ /**
172
+ * Return the current element.
173
+ * Similar to the current() function for arrays in PHP
174
+ * Required by interface Iterator.
175
+ *
176
+ * @return Bronto_Api_Row current element from the collection
177
+ */
178
+ public function current()
179
+ {
180
+ if ($this->valid() === false) {
181
+ return null;
182
+ }
183
+
184
+ // Do we already have a row object for this position?
185
+ if (empty($this->_rows[$this->_pointer])) {
186
+ $this->_rows[$this->_pointer] = new $this->_rowClass(
187
+ array(
188
+ 'apiObject' => $this->_apiObject,
189
+ 'data' => $this->_data[$this->_pointer],
190
+ 'stored' => $this->_stored,
191
+ 'readOnly' => $this->_readOnly
192
+ )
193
+ );
194
+ }
195
+
196
+ // return the row object
197
+ return $this->_rows[$this->_pointer];
198
+ }
199
+
200
+ /**
201
+ * Return the identifying key of the current element.
202
+ * Similar to the key() function for arrays in PHP.
203
+ * Required by interface Iterator.
204
+ *
205
+ * @return int
206
+ */
207
+ public function key()
208
+ {
209
+ return $this->_pointer;
210
+ }
211
+
212
+ /**
213
+ * Move forward to next element.
214
+ * Similar to the next() function for arrays in PHP.
215
+ * Required by interface Iterator.
216
+ *
217
+ * @return void
218
+ */
219
+ public function next()
220
+ {
221
+ ++$this->_pointer;
222
+ }
223
+
224
+ /**
225
+ * Check if there is a current element after calls to rewind() or next().
226
+ * Used to check if we've iterated to the end of the collection.
227
+ * Required by interface Iterator.
228
+ *
229
+ * @return bool False if there's nothing more to iterate over
230
+ */
231
+ public function valid()
232
+ {
233
+ return $this->_pointer >= 0 && $this->_pointer < $this->_count;
234
+ }
235
+
236
+ /**
237
+ * Returns the number of elements in the collection.
238
+ *
239
+ * Implements Countable::count()
240
+ *
241
+ * @return int
242
+ */
243
+ public function count()
244
+ {
245
+ return $this->_count;
246
+ }
247
+
248
+ /**
249
+ * Take the Iterator to position $position
250
+ * Required by interface SeekableIterator.
251
+ *
252
+ * @param int $position the position to seek to
253
+ * @return Bronto_Api_Rowset
254
+ */
255
+ public function seek($position)
256
+ {
257
+ $position = (int) $position;
258
+ if ($position < 0 || $position >= $this->_count) {
259
+ throw new Bronto_Api_Rowset_Exception("Illegal index {$position}");
260
+ }
261
+ $this->_pointer = $position;
262
+ return $this;
263
+ }
264
+
265
+ /**
266
+ * Check if an offset exists
267
+ * Required by the ArrayAccess implementation
268
+ *
269
+ * @param string $offset
270
+ * @return boolean
271
+ */
272
+ public function offsetExists($offset)
273
+ {
274
+ return isset($this->_data[(int) $offset]);
275
+ }
276
+
277
+ /**
278
+ * Get the data for the given offset
279
+ *
280
+ * @param string $offset
281
+ * @return array
282
+ */
283
+ public function offsetGetData($offset)
284
+ {
285
+ $offset = (int) $offset;
286
+ if ($offset < 0 || $offset >= $this->_count) {
287
+ throw new Bronto_Api_Rowset_Exception("Illegal index {$offset}");
288
+ }
289
+
290
+ return $this->_data[$offset];
291
+ }
292
+
293
+ /**
294
+ * Get the row for the given offset
295
+ * Required by the ArrayAccess implementation
296
+ *
297
+ * @param string $offset
298
+ * @return Bronto_Api_Row
299
+ */
300
+ public function offsetGet($offset)
301
+ {
302
+ $offset = (int) $offset;
303
+ if ($offset < 0 || $offset >= $this->_count) {
304
+ throw new Bronto_Api_Rowset_Exception("Illegal index {$offset}");
305
+ }
306
+ $this->_pointer = $offset;
307
+
308
+ return $this->current();
309
+ }
310
+
311
+ /**
312
+ * Does nothing
313
+ * Required by the ArrayAccess implementation
314
+ *
315
+ * @param string $offset
316
+ * @param mixed $value
317
+ */
318
+ public function offsetSet($offset, $value)
319
+ {
320
+ }
321
+
322
+ /**
323
+ * Does nothing
324
+ * Required by the ArrayAccess implementation
325
+ *
326
+ * @param string $offset
327
+ */
328
+ public function offsetUnset($offset)
329
+ {
330
+ }
331
+
332
+ /**
333
+ * Seamlessly iterate over this rowset
334
+ *
335
+ * @return Bronto_Api_Rowset_Iterator
336
+ */
337
+ public function iterate()
338
+ {
339
+ return new Bronto_Api_Rowset_Iterator($this);
340
+ }
341
+
342
+ /**
343
+ * @return bool
344
+ */
345
+ public function hasErrors()
346
+ {
347
+ return !empty($this->_errors);
348
+ }
349
+
350
+ /**
351
+ * @return bool|array
352
+ */
353
+ public function getErrors()
354
+ {
355
+ if ($this->hasErrors()) {
356
+ $errors = array();
357
+ foreach ($this->_errors as $pointer) {
358
+ if ($this->offsetExists($pointer)) {
359
+ $row = $this->offsetGet($pointer);
360
+ $errors[] = array(
361
+ 'code' => $row->getErrorCode(),
362
+ 'message' => $row->getErrorMessage(),
363
+ );
364
+ }
365
+ }
366
+ return $errors;
367
+ }
368
+ return false;
369
+ }
370
+
371
+ /**
372
+ * @return bool|array
373
+ */
374
+ public function getError()
375
+ {
376
+ if ($this->hasErrors()) {
377
+ $error = array(
378
+ 'code' => null,
379
+ 'message' => 'Unknown error',
380
+ );
381
+ foreach ($this->_errors as $pointer) {
382
+ if ($this->offsetExists($pointer)) {
383
+ $row = $this->offsetGet($pointer);
384
+ $error = array(
385
+ 'code' => $row->getErrorCode(),
386
+ 'message' => $row->getErrorMessage(),
387
+ );
388
+ break;
389
+ }
390
+ }
391
+ return $error;
392
+ }
393
+ return false;
394
+ }
395
+ }
lib/Bronto/Api/Rowset/Exception.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_Rowset_Exception extends Bronto_Api_Exception
4
+ {
5
+
6
+ }
lib/Bronto/Api/Rowset/Iterator.php ADDED
@@ -0,0 +1,403 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ */
6
+ class Bronto_Api_Rowset_Iterator implements Iterator, Countable
7
+ {
8
+ /** Iterator Types */
9
+ const TYPE_NONE = 0;
10
+ const TYPE_PAGE = 1;
11
+ const TYPE_DATE = 2;
12
+ const TYPE_STREAM = 3;
13
+
14
+ /**
15
+ * API Object
16
+ *
17
+ * @var Bronto_Api_Object
18
+ */
19
+ protected $_apiObject;
20
+
21
+ /**
22
+ * @var Bronto_Api_Rowset
23
+ */
24
+ protected $_rowset;
25
+
26
+ /**
27
+ * @var int
28
+ */
29
+ protected $_page = 1;
30
+
31
+ /**
32
+ * @var bool
33
+ */
34
+ protected $_newPage = true;
35
+
36
+ /**
37
+ * How many data rows there are (currently)
38
+ *
39
+ * @var int
40
+ */
41
+ protected $_count = 0;
42
+
43
+ /**
44
+ * Iterator pointer
45
+ *
46
+ * @var integer
47
+ */
48
+ protected $_pointer = 0;
49
+
50
+ /**
51
+ * @var int
52
+ */
53
+ protected $_type = self::TYPE_NONE;
54
+
55
+ /**
56
+ * Query field(s) for paging
57
+ *
58
+ * @var array
59
+ */
60
+ protected $_params = array();
61
+
62
+ /**
63
+ * Initial paging value(s)
64
+ *
65
+ * @var array
66
+ */
67
+ protected $_initialParamValues = array();
68
+
69
+ /**
70
+ * Last used paging value(s)
71
+ *
72
+ * @var array
73
+ */
74
+ protected $_lastParamValues = array();
75
+
76
+ /**
77
+ * Next paging value(s) to be used
78
+ *
79
+ * @var array
80
+ */
81
+ protected $_nextParamValues = array();
82
+
83
+ /**
84
+ * Constructor
85
+ *
86
+ * @param array $config
87
+ */
88
+ public function __construct(Bronto_Api_Rowset $rowset)
89
+ {
90
+ $this->_apiObject = $rowset->getApiObject();
91
+
92
+ if (!$this->_apiObject->canIterate()) {
93
+ throw new Bronto_Api_Rowset_Exception(sprintf('Cannot iterate results for %s', $this->_apiObject->getName()));
94
+ }
95
+
96
+ $this->_type = $this->_apiObject->getIteratorType();
97
+ $this->_params = $this->_apiObject->getIteratorParams();
98
+ $this->_rowset = $rowset;
99
+ $this->_count = $rowset->count();
100
+
101
+ // Set initial/next values
102
+ $this->_setupParamValues();
103
+ }
104
+
105
+ /**
106
+ * @return Bronto_Api_Object
107
+ */
108
+ public function getApiObject()
109
+ {
110
+ return $this->_apiObject;
111
+ }
112
+
113
+ protected function _setupParamValues()
114
+ {
115
+ $params = $this->_rowset->getParams();
116
+ $this->_lastParamValues = $params;
117
+
118
+ if (empty($this->_initialParamValues)) {
119
+ $this->_initialParamValues = $params;
120
+ }
121
+
122
+ // Loop through each field we have to check/update
123
+ foreach ($this->_params as $queryParam => $rowField) {
124
+ // Loop through each initial API query params
125
+ foreach ($params as $key => $value) {
126
+ if (!is_array($value)) {
127
+ $value = array($value);
128
+ }
129
+ foreach ($value as $subkey => $subvalue) {
130
+ if ($subkey == $queryParam) {
131
+ switch ($queryParam) {
132
+ case 'readDirection':
133
+ $this->_nextParamValues[$queryParam] = Bronto_Api_Object::DIRECTION_NEXT;
134
+ break;
135
+ case 'pageNumber':
136
+ $this->_nextParamValues[$queryParam] = $subvalue + 1;
137
+ break;
138
+ default:
139
+ $this->_nextParamValues[$queryParam] = $subvalue;
140
+ break;
141
+ }
142
+ }
143
+ }
144
+ }
145
+ }
146
+ }
147
+
148
+ /**
149
+ * @return array
150
+ */
151
+ protected function _getNextParamValues(array $skipParams = array())
152
+ {
153
+ $params = $this->_lastParamValues;
154
+
155
+ // Loop through each field we have to update
156
+ foreach ($this->_params as $queryParam => $rowField) {
157
+ if (in_array($queryParam, $skipParams)) {
158
+ continue;
159
+ }
160
+ // Loop through each API query param
161
+ foreach ($params as $key => $value) {
162
+ if (!is_array($value)) {
163
+ if ($key == $queryParam) {
164
+ $params[$key] = $this->_nextParamValues[$queryParam];
165
+ }
166
+ } else {
167
+ foreach ($value as $subkey => $subvalue) {
168
+ if ($subkey == $queryParam) {
169
+ $params[$key][$subkey] = $this->_nextParamValues[$queryParam];
170
+ }
171
+ }
172
+ }
173
+ }
174
+ }
175
+
176
+ return $params;
177
+ }
178
+
179
+ /**
180
+ * @param int $pad
181
+ * @return int|string
182
+ */
183
+ public function getCurrentPage($pad = false)
184
+ {
185
+ if ($pad !== false) {
186
+ $pad = (int) $pad;
187
+ return sprintf("%0{$pad}d", $this->_page);
188
+ }
189
+
190
+ return $this->_page;
191
+ }
192
+
193
+ /**
194
+ * @return int
195
+ */
196
+ public function getCurrentKey()
197
+ {
198
+ return $this->_pointer;
199
+ }
200
+
201
+ /**
202
+ * Returns the number of elements in the collection.
203
+ *
204
+ * Implements Countable::count()
205
+ *
206
+ * @return int
207
+ */
208
+ public function count()
209
+ {
210
+ return $this->_count;
211
+ }
212
+
213
+ /**
214
+ * Required by interface Iterator.
215
+ *
216
+ * @return void
217
+ */
218
+ public function rewind()
219
+ {
220
+ }
221
+
222
+ /**
223
+ * Return the current element.
224
+ * Similar to the current() function for arrays in PHP
225
+ * Required by interface Iterator.
226
+ *
227
+ * @return Bronto_Api_Row current element from the collection
228
+ */
229
+ public function current()
230
+ {
231
+ if ($this->valid() === false) {
232
+ return null;
233
+ }
234
+
235
+ /* @var $row Bronto_Api_Row */
236
+ $row = $this->_rowset->current();
237
+
238
+ // Loop through each field we have to update
239
+ foreach ($this->_params as $queryParam => $rowField) {
240
+ // Skip fields that are query only
241
+ if (!$rowField) {
242
+ continue;
243
+ }
244
+ if (isset($row->{$rowField}) && !empty($row->{$rowField})) {
245
+ $this->_nextParamValues[$queryParam] = $row->{$rowField};
246
+ if ($row->isDateField($rowField)) {
247
+ $this->_nextParamValues[$queryParam] = date('c', strtotime($row->{$rowField}));
248
+ }
249
+ }
250
+ }
251
+
252
+ return $row;
253
+ }
254
+
255
+ /**
256
+ * Return the identifying key of the current element.
257
+ * Similar to the key() function for arrays in PHP.
258
+ * Required by interface Iterator.
259
+ *
260
+ * @return int
261
+ */
262
+ public function key()
263
+ {
264
+ return $this->_rowset->key();
265
+ }
266
+
267
+ /**
268
+ * Move forward to next element.
269
+ * Similar to the next() function for arrays in PHP.
270
+ * Required by interface Iterator.
271
+ *
272
+ * @return void
273
+ */
274
+ public function next()
275
+ {
276
+ $this->_rowset->next();
277
+ ++$this->_pointer;
278
+ $this->_newPage = false;
279
+ return $this->current();
280
+ }
281
+
282
+ /**
283
+ * Check if there is a current element after calls to rewind() or next().
284
+ * Used to check if we've iterated to the end of the collection.
285
+ * Required by interface Iterator.
286
+ *
287
+ * @return bool False if there's nothing more to iterate over
288
+ */
289
+ public function valid()
290
+ {
291
+ if ($this->_rowset->valid()) {
292
+ return true;
293
+ }
294
+
295
+ return $this->_nextRowset();
296
+ }
297
+
298
+ /**
299
+ * @return bool
300
+ */
301
+ protected function _nextRowset()
302
+ {
303
+ unset($this->_rowset);
304
+
305
+ // Skip some fields under certain circumstances
306
+ $skipParams = array();
307
+ if ($this->_type == self::TYPE_STREAM) {
308
+ $skipParams = $this->_params;
309
+ unset($skipParams['readDirection']);
310
+ }
311
+
312
+ // Make request for the new rowset
313
+ try {
314
+ $params = $this->_getNextParamValues(array_keys($skipParams));
315
+ $this->_rowset = $this->_apiObject->read($params);
316
+ } catch (Exception $e) {
317
+ if ($this->_type == self::TYPE_STREAM) {
318
+ // Reset readDirection
319
+ $this->_nextParamValues['readDirection'] = Bronto_Api_Object::DIRECTION_FIRST;
320
+ // Get params again without skipping
321
+ $params = $this->_getNextParamValues();
322
+ $this->_rowset = $this->_apiObject->read($params);
323
+ } else {
324
+ throw $e;
325
+ }
326
+ }
327
+
328
+ if (!$this->_rowset) {
329
+ throw new Bronto_Api_Rowset_Exception('Retrieving the next Rowset failed');
330
+ }
331
+
332
+ // Increments
333
+ $this->_newPage = true;
334
+ $this->_page = $this->_page + 1;
335
+ $this->_count = $this->_count + $this->_rowset->count();
336
+
337
+ // Re-setup params
338
+ $this->_setupParamValues();
339
+
340
+ return $this->_rowset->valid();
341
+ }
342
+
343
+ /**
344
+ * @return bool
345
+ */
346
+ public function isNewPage()
347
+ {
348
+ return $this->_newPage;
349
+ }
350
+
351
+ /**
352
+ * @return array
353
+ */
354
+ public function getLastParamValues()
355
+ {
356
+ return $this->_lastParamValues;
357
+ }
358
+
359
+ /**
360
+ * @param string $param
361
+ * @return mixed
362
+ */
363
+ public function getLastParamValue($param)
364
+ {
365
+ if (isset($this->_lastParamValues[$param])) {
366
+ return $this->_lastParamValues[$param];
367
+ }
368
+
369
+ foreach ($this->_lastParamValues as $key => $value) {
370
+ if (is_array($value)) {
371
+ if (isset($value[$param])) {
372
+ return $value[$param];
373
+ }
374
+ }
375
+ }
376
+
377
+ return false;
378
+ }
379
+
380
+ /**
381
+ * @return Bronto_Api
382
+ */
383
+ public function getApi()
384
+ {
385
+ return $this->_apiObject->getApi();
386
+ }
387
+
388
+ /**
389
+ * @return string
390
+ */
391
+ public function getLastRequest()
392
+ {
393
+ return $this->_apiObject->getApi()->getLastRequest();
394
+ }
395
+
396
+ /**
397
+ * @return string
398
+ */
399
+ public function getLastResponse()
400
+ {
401
+ return $this->_apiObject->getApi()->getLastResponse();
402
+ }
403
+ }
lib/Bronto/Api/Segment.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ * @link http://community.bronto.com/api/v4/objects/general/segmentobject
6
+ */
7
+ class Bronto_Api_Segment extends Bronto_Api_Object
8
+ {
9
+ /**
10
+ * @var array
11
+ */
12
+ protected $_methods = array(
13
+ 'readSegments' => 'read',
14
+ );
15
+
16
+ /**
17
+ * @param array $filter
18
+ * @param int $pageNumber
19
+ * @return Bronto_Api_Rowset
20
+ */
21
+ public function readAll(array $filter = array(), $pageNumber = 1)
22
+ {
23
+ $params = array();
24
+ $params['filter'] = $filter;
25
+ $params['pageNumber'] = (int) $pageNumber;
26
+ return $this->read($params);
27
+ }
28
+
29
+ /**
30
+ * @param array $data
31
+ */
32
+ public function createRow(array $data = array())
33
+ {
34
+ throw new Bronto_Api_Segment_Exception('You cannot create a Segment row.');
35
+ }
36
+ }
lib/Bronto/Api/Segment/Exception.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Api_Segment_Exception extends Bronto_Api_Exception
4
+ {
5
+
6
+ }
lib/Bronto/Api/Segment/Row.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @property-read string $id
5
+ * @property-read string $name
6
+ * @property-read array $rules
7
+ * @property-read string $lastUpdated
8
+ * @property-read float $activeCount
9
+ * @method Bronto_Api_Segment getApiObject() getApiObject()
10
+ */
11
+ class Bronto_Api_Segment_Row extends Bronto_Api_Row implements Bronto_Api_Delivery_Recipient
12
+ {
13
+ /**
14
+ * @var bool
15
+ */
16
+ protected $_readOnly = true;
17
+
18
+ /**
19
+ * @return Bronto_Api_Segment_Row
20
+ */
21
+ public function read()
22
+ {
23
+ if ($this->id) {
24
+ $params = array('id' => $this->id);
25
+ } elseif ($this->name) {
26
+ $params = array(
27
+ 'name' => array(
28
+ 'value' => $this->name,
29
+ 'operator' => 'EqualTo',
30
+ )
31
+ );
32
+ }
33
+
34
+ parent::_read($params);
35
+ return $this;
36
+ }
37
+
38
+ /**
39
+ * Required by Bronto_Api_Delivery_Recipient
40
+ *
41
+ * @return false
42
+ */
43
+ public function isList()
44
+ {
45
+ return false;
46
+ }
47
+
48
+ /**
49
+ * Required by Bronto_Api_Delivery_Recipient
50
+ *
51
+ * @return false
52
+ */
53
+ public function isContact()
54
+ {
55
+ return false;
56
+ }
57
+
58
+ /**
59
+ * Required by Bronto_Api_Delivery_Recipient
60
+ *
61
+ * @return true
62
+ */
63
+ public function isSegment()
64
+ {
65
+ return true;
66
+ }
67
+ }
lib/Bronto/SoapClient.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Jared Hodak <jhodak@kadro.com>
5
+ */
6
+ class Bronto_SoapClient extends SoapClient
7
+ {
8
+ /**
9
+ * Overriding to replace known invalid xml characters.
10
+ * @see http://www.w3.org/TR/xml/#charsets
11
+ * @return string
12
+ */
13
+ public function __doRequest($request, $location, $action, $version, $one_way = 0) {
14
+ $result = parent::__doRequest($request, $location, $action, $version);
15
+ $result = preg_replace('/[\x{0}-\x{8}\x{B}-\x{C}\x{E}-\x{1F}\x{D800}-\x{DFFF}]/u', '', $result);
16
+ return $result;
17
+ }
18
+ }
lib/Bronto/Util/Colors.php ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ */
6
+ class Bronto_Util_Colors
7
+ {
8
+ /**
9
+ * @see http://media.if-not-true-then-false.com/2010/01/PHP_CLI_Coloring_Class_Example.png
10
+ * @var array
11
+ */
12
+ protected $_attributes = array(
13
+ 'black' => array(
14
+ 'ansi' => '0;30',
15
+ 'hex' => '#2e3336',
16
+ ),
17
+ 'darkgray' => array(
18
+ 'ansi' => '1;30',
19
+ 'hex' => '#1e1e1e',
20
+ ),
21
+ 'blue' => array(
22
+ 'ansi' => '0;34',
23
+ 'hex' => '#3466a5',
24
+ ),
25
+ 'lightblue' => array(
26
+ 'ansi' => '1;34',
27
+ 'hex' => '#3edde0',
28
+ ),
29
+ 'green' => array(
30
+ 'ansi' => '0;32',
31
+ 'hex' => '#4e9a06',
32
+ ),
33
+ 'lightgreen' => array(
34
+ 'ansi' => '1;32',
35
+ 'hex' => '#87d939',
36
+ ),
37
+ 'cyan' => array(
38
+ 'ansi' => '0;36',
39
+ 'hex' => '#07989b',
40
+ ),
41
+ 'lightcyan' => array(
42
+ 'ansi' => '1;36',
43
+ 'hex' => '#39d7da',
44
+ ),
45
+ 'red' => array(
46
+ 'ansi' => '0;31',
47
+ 'hex' => '#cc0000',
48
+ ),
49
+ 'lightred' => array(
50
+ 'ansi' => '1;31',
51
+ 'hex' => '#c83a39',
52
+ ),
53
+ 'purple' => array(
54
+ 'ansi' => '0;35',
55
+ 'hex' => '#75507b',
56
+ ),
57
+ 'lightpurple' => array(
58
+ 'ansi' => '1;35',
59
+ 'hex' => '#aa7faa',
60
+ ),
61
+ 'brown' => array(
62
+ 'ansi' => '0;33',
63
+ 'hex' => '#8d6736',
64
+ ),
65
+ 'yellow' => array(
66
+ 'ansi' => '1;33',
67
+ 'hex' => '#c4a001',
68
+ ),
69
+ 'lightgray' => array(
70
+ 'ansi' => '0;37',
71
+ 'hex' => '#d2d7d0',
72
+ ),
73
+ 'white' => array(
74
+ 'ansi' => '1;37',
75
+ 'hex' => '#ffffff',
76
+ ),
77
+ 'onblack' => array(
78
+ 'ansi' => '40',
79
+ 'hex' => '#2e3336',
80
+ ),
81
+ 'onred' => array(
82
+ 'ansi' => '41',
83
+ 'hex' => '#cc0001',
84
+ ),
85
+ 'ongreen' => array(
86
+ 'ansi' => '42',
87
+ 'hex' => '#4e9a06',
88
+ ),
89
+ 'onyellow' => array(
90
+ 'ansi' => '43',
91
+ 'hex' => '#c4a100',
92
+ ),
93
+ 'onblue' => array(
94
+ 'ansi' => '44',
95
+ 'hex' => '#3466a5',
96
+ ),
97
+ 'onmagenta' => array(
98
+ 'ansi' => '45',
99
+ 'hex' => '#75507b',
100
+ ),
101
+ 'oncyan' => array(
102
+ 'ansi' => '46',
103
+ 'hex' => '#07989b',
104
+ ),
105
+ 'onlightgray' => array(
106
+ 'ansi' => '47',
107
+ 'hex' => '#d4d7d0',
108
+ ),
109
+ );
110
+
111
+ /**
112
+ * @param string|array $codes
113
+ * @param bool $html
114
+ * @return string
115
+ */
116
+ public function color($codes = array(), $html = false)
117
+ {
118
+ $attribute = '';
119
+ if (is_string($codes)) {
120
+ $codes = explode(' ', $codes);
121
+ }
122
+ foreach ($codes as $code) {
123
+ $code = strtolower($code);
124
+ if ($html) {
125
+ if (isset($this->_attributes[$code]['hex'])) {
126
+ if (stripos($code, 'on') === 0) {
127
+ $attribute .= "background-color: {$this->_attributes[$code]['hex']};";
128
+ } else {
129
+ $attribute .= "color: {$this->_attributes[$code]['hex']};";
130
+ }
131
+ } else {
132
+ switch ($code) {
133
+ case 'bold':
134
+ $attribute .= 'font-weight: bold;';
135
+ break;
136
+ default:
137
+ break;
138
+ }
139
+ }
140
+ } else {
141
+ if (isset($this->_attributes[$code]['ansi'])) {
142
+ $attribute .= "{$this->_attributes[$code]['ansi']};";
143
+ }
144
+ }
145
+ }
146
+
147
+ if ($html) {
148
+ return $attribute;
149
+ } else {
150
+ $attribute = substr($attribute, 0, -1);
151
+ return empty($attribute) ? false : chr(27) . "[$attribute" . "m";
152
+ }
153
+ }
154
+
155
+ /**
156
+ * @param string $text
157
+ * @param string|array $codes
158
+ * @param bool $html
159
+ * @return string
160
+ */
161
+ public function colored($text = '', $codes = array(), $html = false)
162
+ {
163
+ $attr = $this->color($codes, $html);
164
+
165
+ if ($html) {
166
+ if (empty($attr)) {
167
+ return false;
168
+ } else {
169
+ return "<span style=\"{$attr}\">{$text}</span>";
170
+ }
171
+ } else {
172
+ return $attr . $text . chr(27) . "[0m";
173
+ }
174
+ }
175
+
176
+ /**
177
+ * @param string $text
178
+ * @param bool $html
179
+ * @return string
180
+ */
181
+ public function parse($text = '', $html = false)
182
+ {
183
+ $matches = array();
184
+ preg_match_all('/(<([\w\s]+)[^>]*>)(.*?)(<\/\\2>)/', $text, $matches, PREG_SET_ORDER);
185
+ foreach ($matches as $value) {
186
+ $codes = explode(' ', trim($value[1], '<>'));
187
+ if ($substring = $this->colored($value[3], $codes, $html)) {
188
+ $text = str_replace($value[0], $substring, $text);
189
+ }
190
+ }
191
+ return $text;
192
+ }
193
+ }
lib/Bronto/Util/CountryCodes.php ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ */
6
+ class Bronto_Util_Country
7
+ {
8
+ public static $codes = array(
9
+ 'AF' => 'Afghanistan',
10
+ 'AX' => 'Aland Islands',
11
+ 'AL' => 'Albania',
12
+ 'DZ' => 'Algeria',
13
+ 'AS' => 'American Samoa',
14
+ 'AD' => 'Andorra',
15
+ 'AO' => 'Angola',
16
+ 'AI' => 'Anguilla',
17
+ 'AQ' => 'Antarctica',
18
+ 'AG' => 'Antigua and Barbuda',
19
+ 'AR' => 'Argentina',
20
+ 'AM' => 'Armenia',
21
+ 'AW' => 'Aruba',
22
+ 'AU' => 'Australia',
23
+ 'AT' => 'Austria',
24
+ 'AZ' => 'Azerbaijan',
25
+ 'BS' => 'Bahamas',
26
+ 'BH' => 'Bahrain',
27
+ 'BD' => 'Bangladesh',
28
+ 'BB' => 'Barbados',
29
+ 'BY' => 'Belarus',
30
+ 'BE' => 'Belgium',
31
+ 'BZ' => 'Belize',
32
+ 'BJ' => 'Benin',
33
+ 'BM' => 'Bermuda',
34
+ 'BT' => 'Bhutan',
35
+ 'BO' => 'Bolivia Plurinational State of',
36
+ 'BA' => 'Bosnia and Herzegovina',
37
+ 'BW' => 'Botswana',
38
+ 'BV' => 'Bouvet Island',
39
+ 'BR' => 'Brazil',
40
+ 'IO' => 'British Indian Ocean Territory',
41
+ 'BN' => 'Brunei Darussalam',
42
+ 'BG' => 'Bulgaria',
43
+ 'BF' => 'Burkina Faso',
44
+ 'BI' => 'Burundi',
45
+ 'KH' => 'Cambodia',
46
+ 'CM' => 'Cameroon',
47
+ 'CA' => 'Canada',
48
+ 'CV' => 'Cape Verde',
49
+ 'KY' => 'Cayman Islands',
50
+ 'CF' => 'Central African Republic',
51
+ 'TD' => 'Chad',
52
+ 'CL' => 'Chile',
53
+ 'CN' => 'China',
54
+ 'CX' => 'Christmas Island',
55
+ 'CC' => 'Cocos (keeling) Islands',
56
+ 'CO' => 'Colombia',
57
+ 'KM' => 'Comoros',
58
+ 'CG' => 'Congo',
59
+ 'CD' => 'Congo the Democratic Republic of the',
60
+ 'CK' => 'Cook Islands',
61
+ 'CR' => 'Costa Rica',
62
+ 'CI' => '"Cote dIvoire"',
63
+ 'HR' => 'Croatia',
64
+ 'CU' => 'Cuba',
65
+ 'CY' => 'Cyprus',
66
+ 'CZ' => 'Czech Republic',
67
+ 'DK' => 'Denmark',
68
+ 'DJ' => 'Djibouti',
69
+ 'DM' => 'Dominica',
70
+ 'DO' => 'Dominican Republic',
71
+ 'EC' => 'Ecuador',
72
+ 'EG' => 'Egypt',
73
+ 'SV' => 'El Salvador',
74
+ 'GQ' => 'Equatorial Guinea',
75
+ 'ER' => 'Eritrea',
76
+ 'EE' => 'Estonia',
77
+ 'ET' => 'Ethiopia',
78
+ 'FK' => 'Falkland Islands (malvinas)',
79
+ 'FO' => 'Faroe Islands',
80
+ 'FJ' => 'Fiji',
81
+ 'FI' => 'Finland',
82
+ 'FR' => 'France',
83
+ 'GF' => 'French Guiana',
84
+ 'PF' => 'French Polynesia',
85
+ 'TF' => 'French Southern Territories',
86
+ 'GA' => 'Gabon',
87
+ 'GM' => 'Gambia',
88
+ 'GE' => 'Georgia',
89
+ 'DE' => 'Germany',
90
+ 'GH' => 'Ghana',
91
+ 'GI' => 'Gibraltar',
92
+ 'GR' => 'Greece',
93
+ 'GL' => 'Greenland',
94
+ 'GD' => 'Grenada',
95
+ 'GP' => 'Guadeloupe',
96
+ 'GU' => 'Guam',
97
+ 'GT' => 'Guatemala',
98
+ 'GG' => 'Guernsey',
99
+ 'GN' => 'Guinea',
100
+ 'GW' => 'Guinea-bissau',
101
+ 'GY' => 'Guyana',
102
+ 'HT' => 'Haiti',
103
+ 'HM' => 'Heard Island and Mcdonald Islands',
104
+ 'VA' => 'Holy See (Vatican City State)',
105
+ 'HN' => 'Honduras',
106
+ 'HK' => 'Hong Kong',
107
+ 'HU' => 'Hungary',
108
+ 'IS' => 'Iceland',
109
+ 'IN' => 'India',
110
+ 'ID' => 'Indonesia',
111
+ 'IR' => 'Iran Islamic Republic of',
112
+ 'IQ' => 'Iraq',
113
+ 'IE' => 'Ireland',
114
+ 'IM' => 'Isle of Man',
115
+ 'IL' => 'Israel',
116
+ 'IT' => 'Italy',
117
+ 'JM' => 'Jamaica',
118
+ 'JP' => 'Japan',
119
+ 'JE' => 'Jersey',
120
+ 'JO' => 'Jordan',
121
+ 'KZ' => 'Kazakhstan',
122
+ 'KE' => 'Kenya',
123
+ 'KI' => 'Kiribati',
124
+ 'KP' => '"Korea Democratic Peoples Republic of"',
125
+ 'KR' => 'Korea Republic of',
126
+ 'KW' => 'Kuwait',
127
+ 'KG' => 'Kyrgyzstan',
128
+ 'LA' => '"Lao Peoples Democratic Republic"',
129
+ 'LV' => 'Latvia',
130
+ 'LB' => 'Lebanon',
131
+ 'LS' => 'Lesotho',
132
+ 'LR' => 'Liberia',
133
+ 'LY' => 'Libyan Arab Jamahiriya',
134
+ 'LI' => 'Liechtenstein',
135
+ 'LT' => 'Lithuania',
136
+ 'LU' => 'Luxembourg',
137
+ 'MO' => 'Macao',
138
+ 'MK' => 'Macedonia the Former Yugoslav Republic of',
139
+ 'MG' => 'Madagascar',
140
+ 'MW' => 'Malawi',
141
+ 'MY' => 'Malaysia',
142
+ 'MV' => 'Maldives',
143
+ 'ML' => 'Mali',
144
+ 'MT' => 'Malta',
145
+ 'MH' => 'Marshall Islands',
146
+ 'MQ' => 'Martinique',
147
+ 'MR' => 'Mauritania',
148
+ 'MU' => 'Mauritius',
149
+ 'YT' => 'Mayotte',
150
+ 'MX' => 'Mexico',
151
+ 'FM' => 'Micronesia Federated States of',
152
+ 'MD' => 'Moldova Republic of',
153
+ 'MC' => 'Monaco',
154
+ 'MN' => 'Mongolia',
155
+ 'ME' => 'Montenegro',
156
+ 'MS' => 'Montserrat',
157
+ 'MA' => 'Morocco',
158
+ 'MZ' => 'Mozambique',
159
+ 'MM' => 'Myanmar',
160
+ 'NA' => 'Namibia',
161
+ 'NR' => 'Nauru',
162
+ 'NP' => 'Nepal',
163
+ 'NL' => 'Netherlands',
164
+ 'AN' => 'Netherlands Antilles',
165
+ 'NC' => 'New Caledonia',
166
+ 'NZ' => 'New Zealand',
167
+ 'NI' => 'Nicaragua',
168
+ 'NE' => 'Niger',
169
+ 'NG' => 'Nigeria',
170
+ 'NU' => 'Niue',
171
+ 'NF' => 'Norfolk Island',
172
+ 'MP' => 'Northern Mariana Islands',
173
+ 'NO' => 'Norway',
174
+ 'OM' => 'Oman',
175
+ 'OT' => 'Other',
176
+ 'PK' => 'Pakistan',
177
+ 'PW' => 'Palau',
178
+ 'PS' => 'Palestinian Territory Occupied',
179
+ 'PA' => 'Panama',
180
+ 'PG' => 'Papua New Guinea',
181
+ 'PY' => 'Paraguay',
182
+ 'PE' => 'Peru',
183
+ 'PH' => 'Philippines',
184
+ 'PN' => 'Pitcairn',
185
+ 'PL' => 'Poland',
186
+ 'PT' => 'Portugal',
187
+ 'PR' => 'Puerto Rico',
188
+ 'QA' => 'Qatar',
189
+ 'RE' => 'REunion',
190
+ 'RO' => 'Romania',
191
+ 'RU' => 'Russian Federation',
192
+ 'RW' => 'Rwanda',
193
+ 'BL' => 'Saint Barthélemy',
194
+ 'SH' => 'Saint Helena Ascension and Tristan da Cunha',
195
+ 'KN' => 'Saint Kitts and Nevis',
196
+ 'LC' => 'Saint Lucia',
197
+ 'MF' => 'Saint Martin',
198
+ 'PM' => 'Saint Pierre and Miquelon',
199
+ 'VC' => 'Saint Vincent and the Grenadines',
200
+ 'WS' => 'Samoa',
201
+ 'SM' => 'San Marino',
202
+ 'ST' => 'Sao Tome and Principe',
203
+ 'SA' => 'Saudi Arabia',
204
+ 'SN' => 'Senegal',
205
+ 'RS' => 'Serbia',
206
+ 'SC' => 'Seychelles',
207
+ 'SL' => 'Sierra Leone',
208
+ 'SG' => 'Singapore',
209
+ 'SK' => 'Slovakia',
210
+ 'SI' => 'Slovenia',
211
+ 'SB' => 'Solomon Islands',
212
+ 'SO' => 'Somalia',
213
+ 'ZA' => 'South Africa',
214
+ 'GS' => 'South Georgia and the South Sandwich Islands',
215
+ 'ES' => 'Spain',
216
+ 'LK' => 'Sri Lanka',
217
+ 'SD' => 'Sudan',
218
+ 'SR' => 'Suriname',
219
+ 'SJ' => 'Svalbard and Jan Mayen',
220
+ 'SZ' => 'Swaziland',
221
+ 'SE' => 'Sweden',
222
+ 'CH' => 'Switzerland',
223
+ 'SY' => 'Syrian Arab Republic',
224
+ 'TW' => 'Taiwan Province of China',
225
+ 'TJ' => 'Tajikistan',
226
+ 'TZ' => 'Tanzania United Republic of',
227
+ 'TH' => 'Thailand',
228
+ 'TL' => 'Timor-leste',
229
+ 'TG' => 'Togo',
230
+ 'TK' => 'Tokelau',
231
+ 'TO' => 'Tonga',
232
+ 'TT' => 'Trinidad and Tobago',
233
+ 'TN' => 'Tunisia',
234
+ 'TR' => 'Turkey',
235
+ 'TM' => 'Turkmenistan',
236
+ 'TC' => 'Turks and Caicos Islands',
237
+ 'TV' => 'Tuvalu',
238
+ 'UG' => 'Uganda',
239
+ 'UA' => 'Ukraine',
240
+ 'AE' => 'United Arab Emirates',
241
+ 'GB' => 'United Kingdom',
242
+ 'US' => 'United States',
243
+ 'UM' => 'United States Minor Outlying Islands',
244
+ 'UY' => 'Uruguay',
245
+ 'UZ' => 'Uzbekistan',
246
+ 'VU' => 'Vanuatu',
247
+ 'VE' => 'Venezuela Bolivarian Republic of',
248
+ 'VN' => 'Viet Nam',
249
+ 'VG' => 'Virgin Islands British',
250
+ 'VI' => 'Virgin Islands U.S.',
251
+ 'WF' => 'Wallis and Futuna',
252
+ 'EH' => 'Western Sahara',
253
+ 'YE' => 'Yemen',
254
+ 'ZM' => 'Zambia',
255
+ 'ZW' => 'Zimbabwe',
256
+ );
257
+ }
lib/Bronto/Util/Retryer/FileRetryer.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ */
6
+ class Bronto_Util_Retryer_FileRetryer implements Bronto_Util_Retryer_RetryerInterface
7
+ {
8
+ /**
9
+ * @var string
10
+ */
11
+ protected $_path;
12
+
13
+ /**
14
+ * @param array $options
15
+ */
16
+ public function __construct(array $options = array())
17
+ {
18
+ $this->_path = sys_get_temp_dir();
19
+
20
+ if (isset($options['path']) && !empty($options['path'])) {
21
+ if (@is_dir($options['path'])) {
22
+ $this->_path = $options['path'];
23
+ } else {
24
+ // Attempt to make it...
25
+ if (@mkdir($options['path'], 0766, true)) {
26
+ $this->_path = $options['path'];
27
+ }
28
+ }
29
+ }
30
+ }
31
+
32
+ /**
33
+ * @param string $filename
34
+ * @return string
35
+ */
36
+ public function getPath($filename = null)
37
+ {
38
+ return $this->_path . (!empty($filename) ? DIRECTORY_SEPARATOR . $filename : '');
39
+ }
40
+
41
+ /**
42
+ * @param Bronto_Api_Object $object
43
+ * @param int $attempts
44
+ * @return string
45
+ */
46
+ public function store(Bronto_Api_Object $object, $attempts = 0)
47
+ {
48
+ if (!@is_dir($this->_path) && !@mkdir($this->_path, 0777, true)) {
49
+ throw new Bronto_Util_RetryerException(sprintf('The Retryer path is not a directory: %s', $this->_path));
50
+ } else {
51
+ if (!@is_writable($this->_path)) {
52
+ throw new Bronto_Util_RetryerException(sprintf('The Retryer path is not a writable: %s', $this->_path));
53
+ }
54
+ }
55
+
56
+ $filename = sprintf(
57
+ '%s_%s_%s_%d.php',
58
+ strtolower($object->getName()),
59
+ str_replace('.', '', microtime()),
60
+ str_pad(rand(0, 1000), 4, ' ', STR_PAD_LEFT),
61
+ (int) $attempts
62
+ );
63
+ $filename = str_replace(' ', '', $filename);
64
+ $fh = @fopen($this->_path . DIRECTORY_SEPARATOR . $filename, 'w');
65
+ $serialized = serialize($object);
66
+ $result = @fwrite($fh, sprintf("<?php return unserialize('%s'); ?>", $serialized));
67
+ @fclose($fh);
68
+
69
+ return $result ? $filename : false;
70
+ }
71
+
72
+ /**
73
+ * @param string $filePath
74
+ * @return Bronto_Api_Object
75
+ */
76
+ protected function _loadObject($filePath)
77
+ {
78
+ if (!@file_exists($filePath)) {
79
+ throw new Bronto_Util_RetryerException(sprintf('Failed to retry file path: %s', $filePath));
80
+ }
81
+
82
+ $parts = explode('_', $filePath);
83
+ $parts = explode('.', $parts[count($parts) - 1]);
84
+
85
+ return array(
86
+ 'object' => include_once $filePath,
87
+ 'attempts' => (int) $parts[0],
88
+ );
89
+ }
90
+
91
+ /**
92
+ * @param string $filePath
93
+ * @return Bronto_Api_Rowset
94
+ */
95
+ public function attempt($filePath)
96
+ {
97
+ $result = $this->_loadObject($filePath);
98
+ $object = $result['object'];
99
+ $attempts = $result['attempts'];
100
+ $method = $object->getLastRequestMethod();
101
+ $data = $object->getLastRequestData();
102
+
103
+ try {
104
+ $rowset = $object->doRequest($method, $data, true);
105
+ } catch (Exception $e) {
106
+ $this->store($object, $attempts++);
107
+ return false;
108
+ }
109
+
110
+ $this->remove($filePath);
111
+
112
+ return $rowset;
113
+ }
114
+
115
+ /**
116
+ * @param string $filePath
117
+ * @return bool
118
+ */
119
+ public function remove($filePath)
120
+ {
121
+ return @unlink($filePath);
122
+ }
123
+ }
lib/Bronto/Util/Retryer/RetryerException.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Bronto_Util_RetryerException extends RuntimeException
4
+ {
5
+
6
+ }
lib/Bronto/Util/Retryer/RetryerInterface.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ interface Bronto_Util_Retryer_RetryerInterface
4
+ {
5
+ /**
6
+ * @param Bronto_Api_Object $object
7
+ * @param int $attempts
8
+ * @return string
9
+ */
10
+ function store(Bronto_Api_Object $object, $attempts = 0);
11
+
12
+ /**
13
+ * @param mixed $identifier
14
+ * @return Bronto_Api_Rowset
15
+ */
16
+ function attempt($identifier);
17
+ }
lib/Bronto/Util/Uuid.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @author Chris Jones <chris.jones@bronto.com>
5
+ */
6
+ class Bronto_Util_Uuid
7
+ {
8
+ /**
9
+ * @param string $value
10
+ * @return string
11
+ */
12
+ public function toString($value)
13
+ {
14
+ if ($value = $this->binaryToString($value)) {
15
+ $this->unstrip($value);
16
+ }
17
+ return false;
18
+ }
19
+
20
+ /**
21
+ * @param string $value
22
+ * @return string
23
+ */
24
+ public function toBinary($value)
25
+ {
26
+ return $this->stringToBinary($this->strip($value));
27
+ }
28
+
29
+ /**
30
+ * @param string $value
31
+ * @return string
32
+ */
33
+ public function stringToBinary($value)
34
+ {
35
+ if (!empty($value)) {
36
+ return pack('H*', $value);
37
+ }
38
+ return false;
39
+ }
40
+
41
+ /**
42
+ * @param string $value
43
+ * @return string
44
+ */
45
+ public function binaryToString($value)
46
+ {
47
+ if (!empty($value)) {
48
+ $value = unpack('H*', $value);
49
+ return array_shift($value);
50
+ }
51
+ return false;
52
+ }
53
+
54
+ /**
55
+ * @param string $value
56
+ * @return string
57
+ */
58
+ public function strip($value)
59
+ {
60
+ return str_replace('-', '', $value);
61
+ }
62
+
63
+ /**
64
+ * @param string $value
65
+ * @return string
66
+ */
67
+ public function unstrip($value)
68
+ {
69
+ if (strlen($value) === 32) {
70
+ return preg_replace('/([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})/', '$1-$2-$3-$4-$5', $value);
71
+ }
72
+
73
+ return $value;
74
+ }
75
+ }
package.xml ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Bronto_Extension</name>
4
+ <version>2.0.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://opensource.org/licenses/osl-3.0.php">OSL</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Drive sales with targeted lifecycle marketing campaigns that convert one-time buyers into repeat customers.</summary>
10
+ <description>&lt;p /&gt;Bronto is a Gold Magento Industry Partner and the leading self-service email marketing provider to the Internet Retailer Top 1000. &#xD;
11
+ &#xD;
12
+ &lt;p /&gt;The Bronto extension helps Magento customers to drive more sales faster by creating highly targeted lifecycle marketing campaigns that convert one-time buyers into repeat customers and motivate them to buy more. &#xD;
13
+ &#xD;
14
+ &lt;p /&gt;The following key features are included in the Bronto extension for Magento:&#xD;
15
+ &#xD;
16
+ &lt;p /&gt;&#x27A2; &lt;strong&gt;Order Import&lt;/strong&gt;&#x2014;Seamlessly import past-purchase information, including complete order history and product details, for more informed and more targeted marketing campaigns. &#xD;
17
+ &#xD;
18
+ &lt;p /&gt;&#x27A2; &lt;strong&gt;Contact Import&lt;/strong&gt;&#x2014;Map customer information collected on your Magento site to contact fields in Bronto and automatically import the data. &#xD;
19
+ &#xD;
20
+ &lt;p /&gt;&#x27A2; &lt;strong&gt;RFM Metrics&lt;/strong&gt;&#x2014;In Bronto, auto-calculate RFM (Recency, Frequency, Monetary Value) metrics for contacts based on the full order history from Magento. This includes Average Order Value, Total Revenue and others. Use these values for improved segmentation.&#xD;
21
+ &#xD;
22
+ &lt;p /&gt;&#x27A2; &lt;strong&gt;Abandoned Cart Reminders&lt;/strong&gt;&#x2014;Trigger a message or message series in Bronto when a cart is abandoned in Magento&#x2014;for both registered and guest abandons; personalize and dynamically populate messages with product information.&#xD;
23
+ &#xD;
24
+ &lt;p /&gt;&#x27A2; &lt;strong&gt;Wish List Reminders&lt;/strong&gt;&#x2014;Automatically trigger email reminders to consumers who have not purchased the items on their wish list within a given time period.&#xD;
25
+ &#xD;
26
+ &lt;p /&gt;&#x27A2; &lt;strong&gt;Transactional Emails&lt;/strong&gt;&#x2014;Send transactional messages, such as order and shipping confirmations, directly through Bronto for maximum control over deliverability and detailed performance metrics. Easily change the look and feel of a message, and add cross- and up-sell offers, without having to involve a developer.&#xD;
27
+ &#xD;
28
+ &lt;p /&gt;&#x27A2; &lt;strong&gt;Support for Multiple Stores&lt;/strong&gt;&#x2014;Managing multiple stores in Magento? Easily change configuration settings and map data from multiple stores to separate accounts in Bronto. &#xD;
29
+ &#xD;
30
+ &lt;p /&gt;&#x27A2; &lt;strong&gt;Newsletter Opt-In&lt;/strong&gt;&#x2014;Automatically add contacts who opt-in for marketing emails on your Magento site to Bronto and keep their subscription status up-to-date.&#xD;
31
+ &#xD;
32
+ &lt;p /&gt;To take advantage of the Bronto extension for Magento, you need a customer subscription to the Bronto Marketing Platform. &#xD;
33
+ &#xD;
34
+ &lt;p /&gt;&lt;strong&gt;Not a Bronto customer? Already a Bronto customer and need help with installation?&lt;/strong&gt; Click &lt;a href="http://mkto.bronto.com/MagentoExtension.html"&gt;here&lt;/a&gt; to engage with us. &#xD;
35
+ &#xD;
36
+ &lt;p /&gt;The Bronto Professional Services team can help you with installation. We have the expertise and resources to help you get up-and-running quickly. &#xD;
37
+ &#xD;
38
+ &lt;p /&gt;&lt;strong&gt;Bronto partner?&lt;/strong&gt; Contact your Bronto partner representative to learn more about this extension. Interested in partnering with Bronto? Click &lt;a href="http://mkto.bronto.com/partnership-application.html"&gt;here&lt;/a&gt;. &#xD;
39
+ &#xD;
40
+ &lt;p /&gt;For installation and configuration documentation for the Bronto Extension for Magento, please visit &lt;a href="http://a.bron.to/magento"&gt;http://a.bron.to/magento&lt;/a&gt;.</description>
41
+ <notes>&lt;p&gt;This is the first release of a new Bronto extension that replaces and deprecates the "Bronto Order Import for Magento," "Bronto Shopping Cart Abandonment," and "Bronto Newsletter Opt-In" extensions. All of the functionality of those extensions is included in this Bronto Extension for Magento.&#xD;
42
+ &#xD;
43
+ &lt;p&gt;For installation and configuration instructions, as well as a full list of new features and known issues, please review the Implementation Guide at &lt;a href="http://a.bron.to/magento"&gt;http://a.bron.to/magento&lt;/a&gt;.&#xD;
44
+ </notes>
45
+ <authors><author><name>Dave Johnson</name><user>BrontoSoftware</user><email>dave.johnson@bronto.com</email></author></authors>
46
+ <date>2013-01-27</date>
47
+ <time>14:42:01</time>
48
+ <contents><target name="magecommunity"><dir name="."><file name="Bronto" hash="d41d8cd98f00b204e9800998ecf8427e"/></dir></target><target name="mageetc"><dir name="modules"><file name="Bronto_All.xml" hash="5a9c06b6313882589765b9bcf0402bbb"/><file name="Bronto_ConflictChecker.xml" hash="1a7dc00b830ca2cc696e67d94b85be5d"/><file name="Bronto_Customer.xml" hash="a11c20f008ee2eae14baa3b549d5adee"/><file name="Bronto_Email.xml" hash="b7cdca4b15753edcefe8b9e0abb780bd"/><file name="Bronto_Newsletter.xml" hash="2115c5225e02ab5d4e56749cc5eff6ad"/><file name="Bronto_Order.xml" hash="63f1537add6088417945657bec98ffe9"/><file name="Bronto_PermissionChecker.xml" hash="55ff239c291529be2dc05799102d24a1"/><file name="Bronto_Reminder.xml" hash="08503ab78994178b822ef9b0add243f9"/><file name="Bronto_Roundtrip.xml" hash="bd2b89f3254e995904da92f025b6321c"/></dir></target><target name="magelib"><dir name="Bronto"><dir name="Api"><dir name="Account"><file name="Exception.php" hash="6048e32e08bac337f37e22918ae92e6a"/><file name="Row.php" hash="de3cb2496c217c25e850573c4d5b2dc2"/></dir><file name="Account.php" hash="30d5ef4bb101748553e239ffe2481183"/><dir name="Activity"><file name="Exception.php" hash="39ac264e8429c000372e849327372471"/><file name="Row.php" hash="b5612081f50d117a7c66f93f9b90382a"/></dir><file name="Activity.php" hash="35aaf580eb62df39b631041937c10187"/><dir name="ApiToken"><file name="Exception.php" hash="ff31b1be1c06581a115aabb7a782d9b5"/><file name="Row.php" hash="1716b6859c05b82301cf28bc7dcca4be"/></dir><file name="ApiToken.php" hash="20ecd2591d6634c42de7b05879c4bc04"/><dir name="Contact"><file name="Exception.php" hash="232fece284740b8e49a5d22ba3082b32"/><file name="Row.php" hash="a85937ee83f1a852372782a8dc1d2eab"/></dir><file name="Contact.php" hash="0413b22277d97b9d9f910281c14a6cea"/><dir name="Conversion"><file name="Exception.php" hash="edaba96e7118b8ce27220ffdabf56721"/><file name="Row.php" hash="495064d7f358f568c0c93b291a267b33"/></dir><file name="Conversion.php" hash="17d45962719271cdc834660cc3478071"/><dir name="Delivery"><file name="Exception.php" hash="c9c746a033ef90ac5e7c70e906331779"/><file name="Recipient.php" hash="9756477b2cbde59ece2b3720c02a5d75"/><file name="Row.php" hash="ca0880566674966a7aa9dee7c4c2c6eb"/></dir><file name="Delivery.php" hash="1866bf3ae809010f630deead7c76a09e"/><dir name="DeliveryGroup"><file name="Exception.php" hash="6ae170c14038a49413580a19ce7ee144"/><file name="Row.php" hash="d5046f7a5dbf39442730f45d17aeaf87"/></dir><file name="DeliveryGroup.php" hash="0e4572ad563c61dd78229af2b6d35cad"/><file name="Exception.php" hash="0df72a2002acff46885dd3978ea95678"/><dir name="Field"><file name="Exception.php" hash="3f900dcdbf5b8b321e48fa6d4a4a5ae1"/><file name="Predefined.php" hash="e876d133b211c4d66ad70ccba7bdff04"/><file name="Row.php" hash="d0c4001b14954dc45e35c8bf8e89cb65"/><file name="TypeGuesser.php" hash="d74ed1da1bd21c93ec68e753edee745f"/></dir><file name="Field.php" hash="4d42365676ef739f72ab50b09595bfa0"/><dir name="List"><file name="Exception.php" hash="ba39e47457265a2042dfaaf0b1c93d70"/><file name="Row.php" hash="bc8f0c84d486f1a41b113529e0da4cc4"/></dir><file name="List.php" hash="589a011d54b9cd6e2400f42fb0391967"/><dir name="Login"><file name="ContactInformation.php" hash="871630e7a0762cb4055183fe9b52b8ea"/><file name="Exception.php" hash="37a401b1206264c7865c62c1c62d394c"/><file name="Row.php" hash="3bfc793c2defa6f538c4b8749dbac22a"/></dir><file name="Login.php" hash="57afd59cd524e57e5a2bdb839a6207e4"/><dir name="Message"><file name="Exception.php" hash="3688ca7320fa9b0a5a3bba80ac4ed072"/><file name="Row.php" hash="ed93a1f123c65324b05e1d2c7b8b4b12"/></dir><file name="Message.php" hash="993e0bfd24d5663078735cbeae9a4b23"/><dir name="MessageRule"><file name="Exception.php" hash="500de77f33962484a640c24521f63659"/><file name="Row.php" hash="5a16b597def2515423e58ab36d17ff01"/></dir><file name="MessageRule.php" hash="bd30a4aa770714ac17b1b33da363aa60"/><file name="Object.php" hash="9681a0940cf96835f2d14b876cce0a4e"/><dir name="Order"><file name="Exception.php" hash="843fd9b527ad8be267664e59e803a2d8"/><file name="Product.php" hash="446161d2fe36cfd849f72066bda8c2ff"/><file name="Row.php" hash="470b921a06f832a0cad81c869038b26e"/></dir><file name="Order.php" hash="9a27755d756a06b82a0cc0d97c315519"/><dir name="Row"><file name="Exception.php" hash="2a48372f5f71cbaad940bc0a62327cff"/></dir><file name="Row.php" hash="459df27d460fd4c3923e860bc8a76a78"/><dir name="Rowset"><file name="Exception.php" hash="5b109a1eef32d14cbc66016fdf65ad9c"/><file name="Iterator.php" hash="0797f8c5a95d47a521ac333e853e6cd3"/></dir><file name="Rowset.php" hash="a10029ba58512887eb7aeb8e40a96a33"/><dir name="Segment"><file name="Exception.php" hash="c0fb3c3a1ed79177f5247abe40adf504"/><file name="Row.php" hash="5211fe7639821a8e413f7832d33dca3c"/></dir><file name="Segment.php" hash="67cf81752cd21a42ad7b6b2ab713c9eb"/></dir><file name="Api.php" hash="2f4d300d9921f4b46faf7d78e34466d9"/><file name="SoapClient.php" hash="f07d2c4551825a1018ddfbd997d660d8"/><dir name="Util"><file name="Colors.php" hash="9bc5a4ce486972d493c82fcb671b416c"/><file name="CountryCodes.php" hash="c666d446d3a156fb2881bf33f2acfc80"/><dir name="Retryer"><file name="FileRetryer.php" hash="6ce89108476048a6e45a7457f53272de"/><file name="RetryerException.php" hash="65ab6cc1f4e71fad55832657f700c653"/><file name="RetryerInterface.php" hash="29aab11684d6eb27439281cd9f6cee76"/></dir><file name="Uuid.php" hash="00f349c1dc57463ebf13639a6bbff6fd"/></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="base"><dir name="default"><dir name="bronto"><file name="cron.css" hash="c7260d3aa14b5945ee76c72dbd914efa"/><dir name="images"><file name="bg_notifications.gif" hash="df73b8aa7e48bb56e0a644245aa3683f"/><file name="logo.jpg" hash="3c6059218195679d99dbb874bdabbd07"/><file name="message_approved.gif" hash="465a056a3ba3d94367f51c3c0b751391"/><file name="message_not_approved.gif" hash="e4f28607f075a105e53fa3113d84bd26"/></dir></dir></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="bronto"><dir name="newsletter"><file name="js.phtml" hash="1b36b8d1f438d5970b4ab0e8f97246d7"/></dir></dir></dir><dir name="layout"><dir name="bronto"><file name="newsletter.xml" hash="b7d4c9b1fb4fabb4255c6df64e98d332"/></dir></dir></dir></dir></dir></target><target name="magelocale"><dir name="en_US"><dir name="template"><dir name="email"><file name="bronto" hash="d41d8cd98f00b204e9800998ecf8427e"/></dir></dir></dir></target></contents>
49
+ <compatible/>
50
+ <dependencies><required><php><min>5.3.0</min><max>5.5.0</max></php><extension><name>soap</name><min></min><max></max></extension><extension><name>openssl</name><min></min><max></max></extension></required></dependencies>
51
+ </package>
skin/adminhtml/base/default/bronto/cron.css ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .bar-red,
2
+ .bar-red span,
3
+ .bar-orange,
4
+ .bar-orange span,
5
+ .bar-yellow,
6
+ .bar-yellow span,
7
+ .bar-green,
8
+ .bar-green span,
9
+ .bar-lightblue,
10
+ .bar-lightblue span,
11
+ .bar-blue,
12
+ .bar-blue span,
13
+ .bar-lightgray,
14
+ .bar-lightgray span,
15
+ .bar-gray,
16
+ .bar-gray span { display:block; height:16px; background-image:url(images/bg_notifications.gif); background-repeat:no-repeat; font:bold 10px/16px Arial, Helvetica, sans-serif; text-transform:uppercase; text-align:center; padding:0 0 0 7px; margin:1px 0; white-space:nowrap; color:#fff; }
17
+
18
+ .bar-red { background-position:0 0; }
19
+ .bar-red span { background-position:100% 0; padding:0 7px 0 0; }
20
+
21
+ .bar-orange { background-position:0 -16px; }
22
+ .bar-orange span { background-position:100% -16px; padding:0 7px 0 0; }
23
+
24
+ .bar-yellow { background-position:0 -32px; }
25
+ .bar-yellow span { background-position:100% -32px; padding:0 7px 0 0; }
26
+
27
+ .bar-green { background-position:0 -48px; }
28
+ .bar-green span { background-position:100% -48px; padding:0 7px 0 0; }
29
+
30
+ .bar-lightblue { background-position:0 -64px; }
31
+ .bar-lightblue span { background-position:100% -64px; padding:0 7px 0 0; }
32
+
33
+ .bar-blue { background-position:0 -80px; }
34
+ .bar-blue span { background-position:100% -80px; padding:0 7px 0 0; }
35
+
36
+ .bar-lightgray { background-position:0 -96px; }
37
+ .bar-lightgray span { background-position:100% -96px; padding:0 7px 0 0; }
38
+
39
+ .bar-gray { background-position:0 -112px; }
40
+ .bar-gray span { background-position:100% -112px; padding:0 7px 0 0; }
41
+
42
+ .bronto-cron {
43
+ margin-top: 8px;
44
+ margin-bottom: 10px;
45
+ padding: 0;
46
+ color: #666;
47
+ }
48
+
49
+ .bronto-cron .form-buttons {
50
+ margin-bottom: 10px;
51
+ padding-right: 4px;
52
+ width: 45%;
53
+ text-align: right;
54
+ }
55
+
56
+ .bronto-cron .form-buttons button {
57
+ margin-left: 5px;
58
+ }
59
+
60
+ .bronto-cron-table {
61
+ border-collapse: collapse;
62
+ clear: both;
63
+ }
64
+
65
+ .bronto-cron-table th {
66
+ background-color: #e5e5e5;
67
+ }
68
+
69
+ .bronto-cron-table td, .bronto-cron-table th {
70
+ border: 1px solid #D6D6D6;
71
+ white-space: nowrap;
72
+ padding: 2px 5px;
73
+ }
74
+
75
+ .bronto-cron-table pre {
76
+ white-space: nowrap;
77
+ }
78
+
79
+ .bronto-progress-bar {
80
+ float: left;
81
+ width: 48%;
82
+ background-color: #ccc;
83
+ border-radius: 2px;
84
+ padding: 2px;
85
+ height: 19px;
86
+ text-align: center;
87
+ color: #000;
88
+ font-size: x-small;
89
+ }
90
+
91
+ .bronto-progress-bar div {
92
+ background-color: #35b963;
93
+ border-radius: 2px;
94
+ text-align: center;
95
+ color: #fff;
96
+ font-size: x-small;
97
+ }
skin/adminhtml/base/default/bronto/images/bg_notifications.gif ADDED
Binary file
skin/adminhtml/base/default/bronto/images/logo.jpg ADDED
Binary file
skin/adminhtml/base/default/bronto/images/message_approved.gif ADDED
Binary file
skin/adminhtml/base/default/bronto/images/message_not_approved.gif ADDED
Binary file