CRM-14478 - ManagedEntities - Add support for 'cleanup' policy ("unused")
authorTim Otten <totten@civicrm.org>
Sun, 11 May 2014 04:54:06 +0000 (21:54 -0700)
committerTim Otten <totten@civicrm.org>
Mon, 26 May 2014 20:04:27 +0000 (13:04 -0700)
CRM/Core/ManagedEntities.php
Civi/Core/Container.php
api/v3/Generic.php
tests/phpunit/CRM/Core/ManagedEntitiesTest.php

index 1aca464609fcfc316960bf1a8333f4bd584e4e58..fd97edb3a9cdcd75c809afdb516f1671de6d3741 100644 (file)
@@ -53,6 +53,8 @@ class CRM_Core_ManagedEntities {
 
   /**
    * Read the managed entity
+   *
+   * @return array|NULL API representation, or NULL if the entity does not exist
    */
   public function get($moduleName, $name) {
     $dao = new CRM_Core_DAO_Managed();
@@ -242,7 +244,29 @@ class CRM_Core_ManagedEntities {
    */
   public function removeStaleEntity($dao) {
     $policy = empty($dao->cleanup) ? 'always' : $dao->cleanup;
-    $doDelete = ($policy == 'always');
+    switch ($policy) {
+      case 'always':
+        $doDelete = TRUE;
+        break;
+      case 'never':
+        $doDelete = FALSE;
+        break;
+      case 'unused':
+        $getRefCount = civicrm_api3($dao->entity_type, 'getrefcount', array(
+          'debug' => 1,
+          'id' => $dao->entity_id
+        ));
+
+        $total = 0;
+        foreach ($getRefCount['values'] as $refCount) {
+          $total += $refCount['count'];
+        }
+
+        $doDelete = ($total == 0);
+        break;
+      default:
+        throw new \Exception('Unrecognized cleanup policy: ' . $policy);
+    }
 
     if ($doDelete) {
       $params = array(
index 504f206666ed38a2e0409d095b9b5eabf80ef752..f70369ad150eb5a373ef5c162ea39e32e720bd70 100644 (file)
@@ -27,10 +27,11 @@ class Container {
   private static $singleton;
 
   /**
+   * @param bool $reset whether to forcibly rebuild the entire container
    * @return \Symfony\Component\DependencyInjection\TaggedContainerInterface
    */
-  public static function singleton() {
-    if (self::$singleton === NULL) {
+  public static function singleton($reset = FALSE) {
+    if ($reset || self::$singleton === NULL) {
       $c = new self();
       self::$singleton = $c->createContainer();
     }
index f2cb0ea73849463710e6e311f307aa31380faa25..75db68b6027deddbd771dc5fd4b97164cc0cc88d 100644 (file)
@@ -113,7 +113,12 @@ function civicrm_api3_generic_getfields($apiRequest) {
   $hypApiRequest = array('entity' => $apiRequest['entity'], 'action' => $action, 'version' => $apiRequest['version']);
   try {
     list ($apiProvider, $hypApiRequest) = \Civi\Core\Container::singleton()->get('civi_api_kernel')->resolve($hypApiRequest);
-    $helper = '_' . $hypApiRequest['function'] . '_spec';
+    if (isset($hypApiRequest['function'])) {
+      $helper = '_' . $hypApiRequest['function'] . '_spec';
+    } else {
+      // not implemented MagicFunctionProvider
+      $helper = NULL;
+    }
   } catch (\Civi\API\Exception\NotImplementedException $e) {
     $helper = NULL;
   }
index 749e71baa643eb823c204285596c3d2ce5541970..1764cc80ff522659a92d3d009966930bf1e918f1 100644 (file)
@@ -6,6 +6,16 @@ require_once 'CiviTest/CiviUnitTestCase.php';
  * Class CRM_Core_ManagedEntitiesTest
  */
 class CRM_Core_ManagedEntitiesTest extends CiviUnitTestCase {
+  /**
+   * @var \Civi\API\Kernel
+   */
+  protected $apiKernel;
+
+  /**
+   * @var \Civi\API\Provider\AdhocProvider
+   */
+  protected $adhocProvider;
+
   /**
    * @var array(string $shortName => CRM_Core_Module $module)
    */
@@ -50,12 +60,17 @@ class CRM_Core_ManagedEntitiesTest extends CiviUnitTestCase {
         'is_reserved' => 1,
       ),
     );
+
+    $this->apiKernel = \Civi\Core\Container::singleton()->get('civi_api_kernel');
+    $this->adhocProvider = new \Civi\API\Provider\AdhocProvider(3, 'CustomSearch');
+    $this->apiKernel->registerApiProvider($this->adhocProvider);
   }
 
   function tearDown() {
     parent::tearDown();
     CRM_Core_DAO::singleValueQuery('DELETE FROM civicrm_managed');
     CRM_Core_DAO::singleValueQuery('DELETE FROM civicrm_option_value WHERE name like "CRM_Example_%"');
+    \Civi\Core\Container::singleton(TRUE);
   }
 
   /**
@@ -191,6 +206,60 @@ class CRM_Core_ManagedEntitiesTest extends CiviUnitTestCase {
     $this->assertEquals($foo['id'], $foo2['id']);
   }
 
+  /**
+   * Set up an active module with one managed-entity using the
+   * policy "cleanup=>never". When the managed-entity goes away,
+   * ensure that the policy is followed (ie the entity is not
+   * deleted).
+   */
+  function testRemoveDeclaration_CleanupUnused() {
+    $decls = array();
+
+    // create first managed entity ('foo')
+    $decls[] = array_merge($this->fixtures['com.example.one-foo'], array(
+      'cleanup' => 'unused'
+    ));
+    $me = new CRM_Core_ManagedEntities($this->modules, $decls);
+    $me->reconcile();
+    $foo = $me->get('com.example.one', 'foo');
+    $this->assertEquals('CRM_Example_One_Foo', $foo['name']);
+    $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"');
+
+    // Override 'getrefcount' ==> The refcount is 1
+    $this->adhocProvider->addAction('getrefcount', 'access CiviCRM', function($apiRequest) {
+      return civicrm_api3_create_success(array(
+        array(
+          'name' => 'mock',
+          'type' => 'mock',
+          'count' => 1,
+        )
+      ));
+    });
+
+    // Later on, entity definition disappears; but we decide not to do any cleanup (per policy)
+    $decls = array();
+    $me = new CRM_Core_ManagedEntities($this->modules, $decls);
+    $me->reconcile();
+    $foo2 = $me->get('com.example.one', 'foo');
+    $this->assertEquals('CRM_Example_One_Foo', $foo2['name']);
+    $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"');
+    $this->assertEquals($foo['id'], $foo2['id']);
+
+
+    // Override 'getrefcount' ==> The refcount is 0
+    $this->adhocProvider->addAction('getrefcount', 'access CiviCRM', function($apiRequest) {
+      return civicrm_api3_create_success(array());
+    });
+
+    // The entity definition disappeared and there's no reference; we decide to cleanup (per policy)
+    $decls = array();
+    $me = new CRM_Core_ManagedEntities($this->modules, $decls);
+    $me->reconcile();
+    $foo3 = $me->get('com.example.one', 'foo');
+    $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"');
+    $this->assertTrue($foo3 === NULL);
+  }
+
   /**
    * Setup an active module with a malformed entity declaration
    */