Payment PropertyBag: Add generic getter, setter methods for convenience
authorRich Lott / Artful Robot <forums@artfulrobot.uk>
Wed, 11 Dec 2019 10:27:56 +0000 (10:27 +0000)
committerRich Lott / Artful Robot <forums@artfulrobot.uk>
Wed, 11 Dec 2019 10:27:56 +0000 (10:27 +0000)
Civi/Payment/PropertyBag.php
tests/phpunit/Civi/Payment/PropertyBagTest.php

index 9341d85b107c7a94934a76d16d734e2c92953a1d..1419892d0a19b85d81f7b45968cf22c458547634 100644 (file)
@@ -261,6 +261,53 @@ class PropertyBag implements \ArrayAccess {
 
   // Public getters, setters.
 
+  /**
+   * Get a property by its name (but still using its getter).
+   *
+   * @param string $prop valid property name, like contactID
+   * @param bool $allowUnset If TRUE, return the default value if the property is
+   *               not set - normal behaviour would be to throw an exception.
+   * @param mixed $default
+   * @param string $label e.g. 'default' or 'old' or 'new'
+   *
+   * @return mixed
+   */
+  public function getter($prop, $allowUnset = FALSE, $default = NULL, $label = 'default') {
+
+    if ((static::$propMap[$prop] ?? NULL) === TRUE) {
+      // This is a standard property that will have a getter method.
+      $getter = 'get' . ucfirst($prop);
+      return (!$allowUnset || $this->has($prop, $label))
+        ? $this->$getter($label)
+        : $default;
+    }
+
+    // This is not a property name we know, but they could be requesting a
+    // custom property.
+    return (!$allowUnset || $this->has($prop, $label))
+      ? $this->getCustomProperty($prop, $label)
+      : $default;
+  }
+
+  /**
+   * Set a property by its name (but still using its setter).
+   *
+   * @param string $prop valid property name, like contactID
+   * @param mixed $value
+   * @param string $label e.g. 'default' or 'old' or 'new'
+   *
+   * @return mixed
+   */
+  public function setter($prop, $value = NULL, $label = 'default') {
+    if ((static::$propMap[$prop] ?? NULL) === TRUE) {
+      // This is a standard property.
+      $setter = 'set' . ucfirst($prop);
+      return $this->$setter($value, $label);
+    }
+    // We don't allow using the setter for custom properties.
+    throw new \BadMethodCallException("Cannot use generic setter with non-standard properties; you must use setCustomProperty for custom properties.");
+  }
+
   /**
    * Get the monetary amount.
    */
index e48c4123154a574ee50b8252089bef99cf25969e..f4ba4320033e9e2aaf6f6ce41a75399b29f6c095 100644 (file)
@@ -229,4 +229,60 @@ class PropertyBagTest extends \PHPUnit\Framework\TestCase implements HeadlessInt
     ];
   }
 
+  /**
+   * Test generic getter, setter methods.
+   *
+   */
+  public function testGetterAndSetter() {
+    $propertyBag = new PropertyBag();
+
+    $propertyBag->setter('contactID', 123);
+    $this->assertEquals(123, $propertyBag->getContactID(), "Failed testing that a valid property was set correctly");
+
+    $result = $propertyBag->getter('contactID');
+    $this->assertEquals(123, $result, "Failed testing the getter on a set property");
+
+    $result = $propertyBag->getter('contactID', TRUE, 456);
+    $this->assertEquals(123, $result, "Failed testing the getter on a set property when providing a default");
+
+    $result = $propertyBag->getter('contributionRecurID', TRUE, 456);
+    $this->assertEquals(456, $result, "Failed testing the getter on an unset property when providing a default");
+
+    try {
+      $result = $propertyBag->getter('contributionRecurID', FALSE);
+      $this->fail("getter called with unset property should throw exception but none was thrown");
+    }
+    catch (\BadMethodCallException $e) {
+    }
+
+    $result = $propertyBag->getter('contribution_recur_id', TRUE, NULL);
+    $this->assertNull($result, "Failed testing the getter on an invalid property when providing a default");
+
+    try {
+      $result = $propertyBag->getter('contribution_recur_id');
+    }
+    catch (\InvalidArgumentException $e) {
+      $this->assertEquals("Attempted to get 'contribution_recur_id' via getCustomProperty - must use using its getter.", $e->getMessage());
+    }
+
+    // Nb. hmmm. the custom property getter does not throw an exception if the property is unset, it just returns NULL.
+    $result = $propertyBag->getter('something_custom');
+    $this->assertNull($result, "Failed testing the getter on an unset custom property when not providing a default");
+
+    try {
+      $propertyBag->setter('some_custom_thing', 'foo');
+      $this->fail("Expected to get an exception when trying to use setter for a non-standard property.");
+    }
+    catch (\BadMethodCallException $e) {
+      $this->assertEquals("Cannot use generic setter with non-standard properties; you must use setCustomProperty for custom properties.", $e->getMessage());
+    }
+
+    // Test labels.
+    $propertyBag->setter('contactID', '100', 'original');
+    $this->assertEquals(123, $propertyBag->getContactID(), "Looks like the setter did not respect the label.");
+    $this->assertEquals(100, $propertyBag->getContactID('original'), "Failed to retrieve the labelled property");
+    $this->assertEquals(100, $propertyBag->getter('contactID', FALSE, NULL, 'original'), "Failed using the getter to retrieve the labelled property");
+
+  }
+
 }