Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure that class-index is up-to-date after toggling extensions #24774

Merged
merged 4 commits into from
Oct 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CRM/Extension/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ public function replace($tmpCodeDir) {
}

$this->refresh();
// It might be useful to reset the container, but (given dev/core#3686) that's not likely to do much.
// \Civi::reset();
// \CRM_Core_Config::singleton(TRUE, TRUE);
CRM_Core_Invoke::rebuildMenuAndCaches(TRUE);
}

Expand Down Expand Up @@ -311,6 +314,8 @@ public function install($keys, $mode = 'install') {
$this->statuses = NULL;
$this->mapper->refresh();
if (!CRM_Core_Config::isUpgradeMode()) {
\Civi::reset();
\CRM_Core_Config::singleton(TRUE, TRUE);
CRM_Core_Invoke::rebuildMenuAndCaches(TRUE);

$schema = new CRM_Logging_Schema();
Expand Down Expand Up @@ -422,6 +427,8 @@ public function disable($keys) {

$this->statuses = NULL;
$this->mapper->refresh();
\Civi::reset();
\CRM_Core_Config::singleton(TRUE, TRUE);
CRM_Core_Invoke::rebuildMenuAndCaches(TRUE);

$this->popProcess($keys);
Expand Down Expand Up @@ -480,6 +487,8 @@ public function uninstall($keys) {

$this->statuses = NULL;
$this->mapper->refresh();
// At the analogous step of `install()` or `disable()`, it would reset the container.
// But here, the extension goes from "disabled=>uninstall". All we really need is to reconcile mgd's.
CRM_Core_Invoke::rebuildMenuAndCaches(TRUE);
$this->popProcess($keys);
}
Expand Down
13 changes: 13 additions & 0 deletions CRM/Extension/Manager/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ public function onPreInstall(CRM_Extension_Info $info) {
$this->callHook($info, 'enable');
}

public function onPostInstall(CRM_Extension_Info $info) {
\Civi\Core\ClassScanner::cache('index')->flush();
}

/**
* @param CRM_Extension_Info $info
*/
Expand Down Expand Up @@ -80,6 +84,7 @@ public function onPreUninstall(CRM_Extension_Info $info) {
* @param CRM_Extension_Info $info
*/
public function onPostUninstall(CRM_Extension_Info $info) {
\Civi\Core\ClassScanner::cache('index')->flush();
}

/**
Expand All @@ -89,6 +94,10 @@ public function onPreDisable(CRM_Extension_Info $info) {
$this->callHook($info, 'disable');
}

public function onPostDisable(CRM_Extension_Info $info) {
\Civi\Core\ClassScanner::cache('index')->flush();
}

/**
* @param CRM_Extension_Info $info
*/
Expand All @@ -97,6 +106,10 @@ public function onPreEnable(CRM_Extension_Info $info) {
$this->callHook($info, 'enable');
}

public function onPostEnable(CRM_Extension_Info $info) {
\Civi\Core\ClassScanner::cache('index')->flush();
}

public function onPostReplace(CRM_Extension_Info $oldInfo, CRM_Extension_Info $newInfo) {
// Like everything, ClassScanner is probably affected by pre-existing/long-standing issue dev/core#3686.
// This may mitigate a couple edge-cases. But really #3686 needs a different+deeper fix.
Expand Down
10 changes: 7 additions & 3 deletions Civi/Core/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,21 +65,25 @@ public function loadContainer() {
return $containerBuilder;
}

$envId = \CRM_Core_Config_Runtime::getId();
$envId = md5(implode(',', array_merge(
[\CRM_Core_Config_Runtime::getId()],
array_column(\CRM_Extension_System::singleton()->getMapper()->getActiveModuleFiles(), 'prefix')
)));
$file = \Civi::paths()->getPath("[civicrm.compile]/CachedCiviContainer.{$envId}.php");
$containerCacheClass = "CachedCiviContainer_{$envId}";
$containerConfigCache = new ConfigCache($file, $cacheMode === 'auto');
if (!$containerConfigCache->isFresh()) {
$containerBuilder = $this->createContainer();
$containerBuilder->compile();
$dumper = new PhpDumper($containerBuilder);
$containerConfigCache->write(
$dumper->dump(['class' => 'CachedCiviContainer']),
$dumper->dump(['class' => $containerCacheClass]),
$containerBuilder->getResources()
);
}

require_once $file;
$c = new \CachedCiviContainer();
$c = new $containerCacheClass();
return $c;
}

Expand Down
35 changes: 35 additions & 0 deletions tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Civi\Api4\DedupeRule;
use Civi\Api4\DedupeRuleGroup;
use Civi\Api4\Email;
use Civi\Api4\Import;
use Civi\Api4\Note;
use Civi\Api4\OptionValue;
use Civi\Api4\UserJob;
Expand All @@ -31,6 +32,26 @@ class CRM_Contribute_Import_Parser_ContributionTest extends CiviUnitTestCase {
*/
protected $entity = 'Contribution';

/**
* These extensions are inactive at the start. They may be activated during the test. They should be deactivated at the end.
*
* For the moment, the test is simply hard-coded to cleanup in a specific order. It's tempting to auto-detect and auto-uninstall these.
* However, the shape of their dependencies makes it tricky to auto-uninstall (e.g. some exts have managed-entities that rely on other
* exts -- you need to fully disable+uninstall the downstream managed-entity-ext before disabling or uninstalling the upstream
* entity-provider-ext).
*
* You may need to edit `$toggleExts` whenever the dependency-graph changes.
*
* @var string[]
*/
protected $toggleExts = ['civiimport', 'org.civicrm.search_kit', 'org.civicrm.afform', 'authx'];

protected function setUp(): void {
parent::setUp();
$origExtensions = array_column(CRM_Extension_System::singleton()->getMapper()->getActiveModuleFiles(), 'fullName');
$this->assertEquals([], array_intersect($origExtensions, $this->toggleExts), 'These extensions may be enabled and disabled during the test. The start-state and end-state should be the same. It appears that we have an unexpected start-state. Perhaps another test left us with a weird start-state?');
}

/**
* Cleanup function.
*
Expand All @@ -43,6 +64,10 @@ public function tearDown(): void {
DedupeRule::delete()
->addWhere('rule_table', '!=', 'civicrm_email')
->addWhere('dedupe_rule_group_id.name', '=', 'IndividualUnsupervised')->execute();
foreach ($this->toggleExts as $ext) {
CRM_Extension_System::singleton()->getManager()->disable([$ext]);
CRM_Extension_System::singleton()->getManager()->uninstall([$ext]);
}
parent::tearDown();
}

Expand Down Expand Up @@ -818,4 +843,14 @@ protected function addToDedupeRule(): void {
]);
}

/**
* Test the Import api works from the extension when the extension is enabled after the import.
*/
public function testEnableExtension(): void {
$this->importContributionsDotCSV();
$this->callAPISuccess('Extension', 'enable', ['key' => 'civiimport']);
$result = Import::get($this->userJobID)->execute();
$this->assertEquals('ERROR', $result->first()['_status']);
}

}