Managed Entity reconciliation fails if entity exists without Managed entity
Overview
Follow along now: "Managed Entities" involve both a Managed
entity and the entity being managed. If the managed entity exists but the corresponding Managed
entity does not, errors are thrown.
For example, if an extension provides a .mgd.php
file specifying a PaymentProcessorType
entity, the reconciliation process will create the PaymentProcessorType
entity and a Managed
entity and then manage updates or deletion when the extension is updated or uninstalled.
In some (unknown) circumstances, the Managed
entity does not exist but the managed (eg PaymentProcessorType
) entity does exist. CRM_Core_ManagedEntities::reconcile()
does not check for the existence of the PaymentProcessorType
entity and so attempts to create a duplicate which fails. This happens any time a cache clear occurs.
Reproduction steps
I don't know how this has occurred on live systems, but to simulate:
- Install Stripe (or other extension with
.mgd.php
) - Delete the
Managed
entity for Stripe:cv api4 Managed.delete +w 'name = "Stripe"'
cv flush
Current behaviour
$ cv flush
Flushing system caches
Error: API Call Failed: Array
(
[entity] => System
[action] => flush
[params] => Array
(
[debug] => 1
[version] => 3
)
[result] => Array
(
[trace] => #0 /opt/buildkit/build/dmaster/web/sites/all/modules/civicrm/CRM/Core/ManagedEntities.php(192): CRM_Core_ManagedEntities->onApiError()
#1 /opt/buildkit/build/dmaster/web/sites/all/modules/civicrm/CRM/Core/ManagedEntities.php(152): CRM_Core_ManagedEntities->insertNewEntity()
#2 /opt/buildkit/build/dmaster/web/sites/all/modules/civicrm/CRM/Core/ManagedEntities.php(113): CRM_Core_ManagedEntities->reconcileEntities()
#3 /opt/buildkit/build/dmaster/web/sites/all/modules/civicrm/CRM/Core/Invoke.php(417): CRM_Core_ManagedEntities->reconcile()
#4 /opt/buildkit/build/dmaster/web/sites/all/modules/civicrm/api/v3/System.php(33): CRM_Core_Invoke::rebuildMenuAndCaches()
#5 /opt/buildkit/build/dmaster/web/sites/all/modules/civicrm/Civi/API/Provider/MagicFunctionProvider.php(89): civicrm_api3_system_flush()
#6 /opt/buildkit/build/dmaster/web/sites/all/modules/civicrm/Civi/API/Kernel.php(158): Civi\API\Provider\MagicFunctionProvider->invoke()
#7 /opt/buildkit/build/dmaster/web/sites/all/modules/civicrm/Civi/API/Kernel.php(81): Civi\API\Kernel->runRequest()
#8 /opt/buildkit/build/dmaster/web/sites/all/modules/civicrm/api/api.php(22): Civi\API\Kernel->runSafe()
#9 phar:///opt/buildkit/bin/cv/src/Command/BaseCommand.php(63): civicrm_api()
#10 phar:///opt/buildkit/bin/cv/src/Command/FlushCommand.php(37): Civi\Cv\Command\BaseCommand->callApiSuccess()
#11 phar:///opt/buildkit/bin/cv/vendor/symfony/console/Command/Command.php(255): Civi\Cv\Command\FlushCommand->execute()
#12 phar:///opt/buildkit/bin/cv/vendor/symfony/console/Application.php(1009): Symfony\Component\Console\Command\Command->run()
#13 phar:///opt/buildkit/bin/cv/vendor/symfony/console/Application.php(273): Symfony\Component\Console\Application->doRunCommand()
#14 phar:///opt/buildkit/bin/cv/src/Application.php(82): Symfony\Component\Console\Application->doRun()
#15 phar:///opt/buildkit/bin/cv/vendor/symfony/console/Application.php(149): Civi\Cv\Application->doRun()
#16 phar:///opt/buildkit/bin/cv/src/Application.php(49): Symfony\Component\Console\Application->run()
#17 phar:///opt/buildkit/bin/cv/bin/cv(27): Civi\Cv\Application::main()
#18 /opt/buildkit/bin/cv(14): require('phar:///opt/bui...')
#19 {main}
[is_error] => 1
[error_message] => API error: DB Error: already exists on PaymentProcessorType.create( entity name Stripe)
)
)
Expected behaviour
No error - or at least a helpful error message.
I think reconcile()
could just create the missing Managed
entity but there may be other ramifications of doing that.
Environment information
- CiviCRM: Master
Comments
Anything else you would like the reviewer to note.