2 namespace Civi\Payment
;
4 use Civi\Test\HeadlessInterface
;
5 use Civi\Test\TransactionalInterface
;
10 class PropertyBagTest
extends \PHPUnit\Framework\TestCase
implements HeadlessInterface
, TransactionalInterface
{
13 * @return \Civi\Test\CiviEnvBuilder
15 public function setUpHeadless() {
16 return \Civi\Test
::headless()->apply();
20 * Test we can set a contact ID.
22 public function testSetContactID() {
24 $propertyBag = new PropertyBag();
25 $propertyBag->setContactID(123);
26 $this->assertEquals(123, $propertyBag->getContactID());
28 // Same but this time set contact ID with string.
29 // (php should throw its own warnings about this because of the signature)
30 $propertyBag = new PropertyBag();
31 $propertyBag->setContactID('123');
32 $this->assertInternalType('int', $propertyBag->getContactID());
33 $this->assertEquals(123, $propertyBag->getContactID());
35 // Test we can have different labels
36 $propertyBag = new PropertyBag();
37 $propertyBag->setContactID(123);
38 $propertyBag->setContactID(456, 'new');
39 $this->assertEquals(123, $propertyBag->getContactID());
40 $this->assertEquals(456, $propertyBag->getContactID('new'));
44 * Test we cannot set an invalid contact ID.
46 * @expectedException \InvalidArgumentException
48 public function testSetContactIDFailsIfInvalid() {
49 $propertyBag = new PropertyBag();
50 $propertyBag->setContactID(0);
54 * Test we can set a contact ID the wrong way
56 public function testSetContactIDLegacyWay() {
57 $propertyBag = new PropertyBag();
58 $propertyBag['contactID'] = 123;
59 $this->assertEquals(123, $propertyBag->getContactID());
60 $this->assertEquals(123, $propertyBag['contactID']);
61 // There should not be any warnings yet.
62 $this->assertEquals("", $propertyBag->lastWarning
);
64 // Now access via legacy name - should work but generate warning.
65 $this->assertEquals(123, $propertyBag['contact_id']);
66 $this->assertEquals("We have translated 'contact_id' to 'contactID' for you, but please update your code to use the propper setters and getters.", $propertyBag->lastWarning
);
68 // Repeat but this time set the property using a legacy name, fetch by new name.
69 $propertyBag = new PropertyBag();
70 $propertyBag['contact_id'] = 123;
71 $this->assertEquals("We have translated 'contact_id' to 'contactID' for you, but please update your code to use the propper setters and getters.", $propertyBag->lastWarning
);
72 $this->assertEquals(123, $propertyBag->getContactID());
73 $this->assertEquals(123, $propertyBag['contactID']);
74 $this->assertEquals(123, $propertyBag['contact_id']);
78 * Test that emails set by the legacy method of 'email-5' can be retrieved with getEmail.
80 public function testSetBillingEmailLegacy() {
81 $localPropertyBag = new PropertyBag();
82 $localPropertyBag->mergeLegacyInputParams(['email-' . \CRM_Core_BAO_LocationType
::getBilling() => 'a@b.com']);
83 $this->assertEquals('a@b.com', $localPropertyBag->getEmail());
87 * Test that null is valid for recurring contribution ID.
89 * See https://github.com/civicrm/civicrm-core/pull/17292
91 public function testRecurProcessorIDNull() {
92 $bag = new PropertyBag();
93 $bag->setRecurProcessorID(NULL);
94 $value = $bag->getRecurProcessorID();
95 $this->assertNull($value);
100 public function testMergeInputs() {
101 $propertyBag = new PropertyBag();
102 $propertyBag->mergeLegacyInputParams([
104 'contributionRecurID' => 456,
106 $this->assertEquals('We have merged input params into the property bag for now but please rewrite code to not use this.', $propertyBag->lastWarning
);
107 $this->assertEquals(123, $propertyBag->getContactID());
108 $this->assertEquals(456, $propertyBag->getContributionRecurID());
112 * Test we can set and access custom props.
114 public function testSetCustomProp() {
115 $propertyBag = new PropertyBag();
116 $propertyBag->setCustomProperty('customThingForMyProcessor', 'fidget');
117 $this->assertEquals('fidget', $propertyBag->getCustomProperty('customThingForMyProcessor'));
118 $this->assertEquals('', $propertyBag->lastWarning
);
120 // Test we can do this with array, although we should get a warning.
121 $propertyBag = new PropertyBag();
122 $propertyBag['customThingForMyProcessor'] = 'fidget';
123 $this->assertEquals('fidget', $propertyBag->getCustomProperty('customThingForMyProcessor'));
124 $this->assertEquals("Unknown property 'customThingForMyProcessor'. We have merged this in for now as a custom property. Please rewrite your code to use PropertyBag->setCustomProperty if it is a genuinely custom property, or a standardised setter like PropertyBag->setContactID for standard properties", $propertyBag->lastWarning
);
128 * Test we can't set a custom prop that we know about.
130 * @expectedException \InvalidArgumentException
131 * @expectedExceptionMessage Attempted to set 'contactID' via setCustomProperty - must use using its setter.
133 public function testSetCustomPropFails() {
134 $propertyBag = new PropertyBag();
135 $propertyBag->setCustomProperty('contactID', 123);
140 * @dataProvider otherParamsDataProvider
142 public function testOtherParams($prop, $legacy_names, $valid_values, $invalid_values) {
143 $setter = 'set' . ucfirst($prop);
144 $getter = 'get' . ucfirst($prop);
146 // Using the setter and getter, check we can pass stuff in and get expected out.
147 foreach ($valid_values as $_) {
148 list($given, $expect) = $_;
149 $propertyBag = new PropertyBag();
151 $propertyBag->$setter($given);
153 catch (\Exception
$e) {
154 $this->fail("Expected to be able to set '$prop' to '$given' but got " . get_class($e) . ": " . $e->getMessage());
157 $this->assertEquals($expect, $propertyBag->$getter());
159 catch (\Exception
$e) {
160 $this->fail("Expected to be able to call $getter, having called $setter with '$given' but got " . get_class($e) . ": " . $e->getMessage());
163 // Using the setter and getter, check we get an error for invalid data.
164 foreach ($invalid_values as $given) {
166 $propertyBag = new PropertyBag();
167 $propertyBag->$setter($given);
169 catch (\InvalidArgumentException
$e) {
170 // counts this assertion.
171 $this->assertTrue(TRUE);
174 $this->fail("Expected an error trying to set $prop to " . json_encode($given) . " but did not get one.");
177 // Check array access for the proper property name and any aliases.
178 foreach (array_merge([$prop], $legacy_names) as $name) {
179 // Check array access
180 foreach ($valid_values as $_) {
181 list($given, $expect) = $_;
182 $propertyBag = new PropertyBag();
183 $propertyBag[$name] = $given;
184 $this->assertEquals($expect, $propertyBag->$getter(), "Failed to set $prop via array access on $name");
185 // Nb. I don't feel the need to repeat all the checks above for every alias.
186 // We only really need to test that the array access works for each alias.
193 * Test the require method works.
195 public function testRequire() {
196 $propertyBag = new PropertyBag();
197 $propertyBag->setContactID(123);
198 $propertyBag->setDescription('foo');
199 // This one should not error.
200 $propertyBag->require(['contactID', 'description']);
202 $propertyBag->require(['contactID', 'description', 'contributionID', 'somethingthatdoesntexist']);
204 catch (\InvalidArgumentException
$e) {
205 $this->assertEquals('Required properties missing: contributionID, somethingthatdoesntexist', $e->getMessage());
210 * Test retrieves using CRM_Utils_Array::value still work.
212 public function testUtilsArray() {
213 $propertyBag = new PropertyBag();
214 $propertyBag->setContactID(123);
215 $this->assertEquals(123, \CRM_Utils_Array
::value('contact_id', $propertyBag));
217 // Test that using utils array value to get a nonexistent property returns the default.
218 $this->assertEquals(456, \CRM_Utils_Array
::value('ISawAManWhoWasntThere', $propertyBag, 456));
223 * Data provider for testOtherParams
226 public function otherParamsDataProvider() {
227 $valid_bools = [['0' , FALSE], ['', FALSE], [0, FALSE], [FALSE, FALSE], [TRUE, TRUE], [1, TRUE], ['1', TRUE]];
228 $valid_strings = [['foo' , 'foo'], ['', '']];
229 $valid_strings_inc_null = [['foo' , 'foo'], ['', ''], [NULL, '']];
230 $valid_ints = [[123, 123], ['123', 123]];
231 $invalid_ints = [-1, 0, NULL, ''];
233 ['billingStreetAddress', [], $valid_strings_inc_null, []],
234 ['billingSupplementalAddress1', [], $valid_strings_inc_null, []],
235 ['billingSupplementalAddress2', [], $valid_strings_inc_null, []],
236 ['billingSupplementalAddress3', [], $valid_strings_inc_null, []],
237 ['billingCity', [], $valid_strings_inc_null, []],
238 ['billingPostalCode', [], $valid_strings_inc_null, []],
239 ['billingCounty', [], $valid_strings_inc_null, []],
240 ['billingCountry', [], [['GB', 'GB'], ['NZ', 'NZ']], ['XX', '', NULL, 0]],
241 ['contributionID', ['contribution_id'], $valid_ints, $invalid_ints],
242 ['contributionRecurID', ['contribution_recur_id'], $valid_ints, $invalid_ints],
243 ['description', [], [['foo' , 'foo'], ['', '']], []],
244 ['feeAmount', ['fee_amount'], [[1.23, 1.23], ['4.56', 4.56]], [NULL]],
245 ['firstName', [], $valid_strings_inc_null, []],
246 ['invoiceID', ['invoice_id'], $valid_strings, []],
247 ['isBackOffice', ['is_back_office'], $valid_bools, [NULL]],
248 ['isRecur', ['is_recur'], $valid_bools, [NULL]],
249 ['lastName', [], $valid_strings_inc_null, []],
250 ['paymentToken', [], $valid_strings, []],
251 ['recurFrequencyInterval', ['frequency_interval'], $valid_ints, $invalid_ints],
252 ['recurFrequencyUnit', [], [['month', 'month'], ['day', 'day'], ['year', 'year']], ['', NULL, 0]],
253 ['recurProcessorID', [], [['foo', 'foo']], [str_repeat('x', 256)]],
254 ['transactionID', ['transaction_id'], $valid_strings, []],
255 ['trxnResultCode', [], $valid_strings, []],
260 * Test generic getter, setter methods.
263 public function testGetterAndSetter() {
264 $propertyBag = new PropertyBag();
266 $propertyBag->setter('contactID', 123);
267 $this->assertEquals(123, $propertyBag->getContactID(), "Failed testing that a valid property was set correctly");
269 $result = $propertyBag->getter('contactID');
270 $this->assertEquals(123, $result, "Failed testing the getter on a set property");
272 $result = $propertyBag->getter('contactID', TRUE, 456);
273 $this->assertEquals(123, $result, "Failed testing the getter on a set property when providing a default");
275 $result = $propertyBag->getter('contributionRecurID', TRUE, 456);
276 $this->assertEquals(456, $result, "Failed testing the getter on an unset property when providing a default");
279 $result = $propertyBag->getter('contributionRecurID', FALSE);
280 $this->fail("getter called with unset property should throw exception but none was thrown");
282 catch (\BadMethodCallException
$e) {
285 $result = $propertyBag->getter('contribution_recur_id', TRUE, NULL);
286 $this->assertNull($result, "Failed testing the getter on an invalid property when providing a default");
289 $result = $propertyBag->getter('contribution_recur_id');
291 catch (\InvalidArgumentException
$e) {
292 $this->assertEquals("Attempted to get 'contribution_recur_id' via getCustomProperty - must use using its getter.", $e->getMessage());
295 // Nb. hmmm. the custom property getter does not throw an exception if the property is unset, it just returns NULL.
296 $result = $propertyBag->getter('something_custom');
297 $this->assertNull($result, "Failed testing the getter on an unset custom property when not providing a default");
300 $propertyBag->setter('some_custom_thing', 'foo');
301 $this->fail("Expected to get an exception when trying to use setter for a non-standard property.");
303 catch (\BadMethodCallException
$e) {
304 $this->assertEquals("Cannot use generic setter with non-standard properties; you must use setCustomProperty for custom properties.", $e->getMessage());
308 $propertyBag->setter('contactID', '100', 'original');
309 $this->assertEquals(123, $propertyBag->getContactID(), "Looks like the setter did not respect the label.");
310 $this->assertEquals(100, $propertyBag->getContactID('original'), "Failed to retrieve the labelled property");
311 $this->assertEquals(100, $propertyBag->getter('contactID', FALSE, NULL, 'original'), "Failed using the getter to retrieve the labelled property");