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

Upgrade civix-generated code to civix format version 25.01.1 #55

Merged
merged 1 commit into from
Feb 25, 2025
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
8 changes: 4 additions & 4 deletions info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@
<url desc="Support">https://github.com/systopia/de.systopia.moregreetings/issues</url>
<url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
</urls>
<releaseDate></releaseDate>
<releaseDate/>
<version>1.3-dev</version>
<develStage>dev</develStage>
<compatibility>
<ver>5.38</ver>
<ver>5.75</ver>
</compatibility>
<comments/>
<civix>
<namespace>CRM/Moregreetings</namespace>
<format>23.02.1</format>
<format>25.01.1</format>
</civix>
<mixins>
<mixin>[email protected]</mixin>
<mixin>[email protected]</mixin>
<mixin>smarty-v2@1.0.0</mixin>
<mixin>[email protected].3</mixin>
</mixins>
<classloader>
<psr0 prefix="CRM_" path="."/>
Expand Down
28 changes: 28 additions & 0 deletions mixin/lib/[email protected]/pathload.main.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php
namespace CiviMix\Schema;

\pathload()->activatePackage('civimix-schema@5', __DIR__, [
'reloadable' => TRUE,
// The civimix-schema library specifically supports installation processes. From a
// bootstrap/service-availability POV, this is a rough environment which leads to
// the "Multi-Activation Issue" and "Multi-Download Issue". To adapt to them,
// civimix-schema follows "Reloadable Library" patterns.
// More information: https://github.com/totten/pathload-poc/blob/master/doc/issues.md
]);

// When reloading, we make newer instance of the Facade object.
$GLOBALS['CiviMixSchema'] = require __DIR__ . '/src/CiviMixSchema.php';

if (!interface_exists(__NAMESPACE__ . '\SchemaHelperInterface')) {
require __DIR__ . '/src/SchemaHelperInterface.php';
}

// \CiviMix\Schema\loadClass() is a facade. The facade should remain identical across versions.
if (!function_exists(__NAMESPACE__ . '\loadClass')) {

function loadClass(string $class) {
return $GLOBALS['CiviMixSchema']->loadClass($class);
}

spl_autoload_register(__NAMESPACE__ . '\loadClass');
}
181 changes: 181 additions & 0 deletions mixin/lib/[email protected]/src/AutomaticUpgrader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
<?php

namespace CiviMix\Schema;

use Civi\Test\Invasive;

/**
* The "AutomaticUpgrader" will create and destroy the SQL tables
* using schema files (`SchemaHelper`). It also calls-out to any custom
* upgrade code (eg `CRM_Myext_Upgrader`).
*
* To simplify backport considerations, `AutomaticUpgrader` does not have formal name.
* It is accessed via aliases like "CiviMix\Schema\*\AutomaticUpgrader".
*
* Target: CiviCRM v5.38+
*/
return new class() implements \CRM_Extension_Upgrader_Interface {

use \CRM_Extension_Upgrader_IdentityTrait {

init as initIdentity;

}

/**
* Optionally delegate to "CRM_Myext_Upgrader" or "Civi\Myext\Upgrader".
*
* @var \CRM_Extension_Upgrader_Interface|null
*/
private $customUpgrader;

public function init(array $params) {
$this->initIdentity($params);
if ($info = $this->getInfo()) {
if ($class = $this->getDelegateUpgraderClass($info)) {
$this->customUpgrader = new $class();
$this->customUpgrader->init($params);
if ($errors = $this->checkDelegateCompatibility($this->customUpgrader)) {
throw new \CRM_Core_Exception("AutomaticUpgrader is not compatible with $class:\n" . implode("\n", $errors));
}
}
}
}

public function notify(string $event, array $params = []) {
$info = $this->getInfo();
if (!$info) {
return;
}

if ($event === 'install') {
$GLOBALS['CiviMixSchema']->getHelper($this->getExtensionKey())->install();
}

if ($this->customUpgrader) {
$result = $this->customUpgrader->notify($event, $params);
// for upgrade checks, we need to pass check results up to the caller
// (for now - could definitely be more elegant!)
if ($event === 'upgrade') {
return $result;
}
}

if ($event === 'uninstall') {
$GLOBALS['CiviMixSchema']->getHelper($this->getExtensionKey())->uninstall();
}
}

/**
* Civix-based extensions have a conventional name for their upgrader class ("CRM_Myext_Upgrader"
* or "Civi\Myext\Upgrader"). Figure out if this class exists.
*
* @param \CRM_Extension_Info $info
* @return string|null
* Ex: 'CRM_Myext_Upgrader' or 'Civi\Myext\Upgrader'
*/
public function getDelegateUpgraderClass(\CRM_Extension_Info $info): ?string {
$candidates = [];

if (!empty($info->civix['namespace'])) {
$namespace = $info->civix['namespace'];
$candidates[] = sprintf('%s_Upgrader', str_replace('/', '_', $namespace));
$candidates[] = sprintf('%s\\Upgrader', str_replace('/', '\\', $namespace));
}

foreach ($candidates as $candidate) {
if (class_exists($candidate)) {
return $candidate;
}
}

return NULL;
}

public function getInfo(): ?\CRM_Extension_Info {
try {
return \CRM_Extension_System::singleton()->getMapper()->keyToInfo($this->extensionName);
}
catch (\CRM_Extension_Exception_ParseException $e) {
\Civi::log()->error("Parse error in extension " . $this->extensionName . ": " . $e->getMessage());
return NULL;
}
}

/**
* @param \CRM_Extension_Upgrader_Interface $upgrader
* @return array
* List of error messages.
*/
public function checkDelegateCompatibility($upgrader): array {
$class = get_class($upgrader);

$errors = [];

if (!($upgrader instanceof \CRM_Extension_Upgrader_Base)) {
$errors[] = "$class is not based on CRM_Extension_Upgrader_Base.";
return $errors;
}

// In the future, we will probably modify AutomaticUpgrader to build its own
// sequence of revisions (based on other sources of data). AutomaticUpgrader
// is only regarded as compatible with classes that strictly follow the standard revision-model.
$methodNames = [
'appendTask',
'onUpgrade',
'getRevisions',
'getCurrentRevision',
'setCurrentRevision',
'enqueuePendingRevisions',
'hasPendingRevisions',
];
foreach ($methodNames as $methodName) {
$method = new \ReflectionMethod($upgrader, $methodName);
if ($method->getDeclaringClass()->getName() !== 'CRM_Extension_Upgrader_Base') {
$errors[] = "To ensure future interoperability, AutomaticUpgrader only supports {$class}::{$methodName}() if it's inherited from CRM_Extension_Upgrader_Base";
}
}

return $errors;
}

public function __set($property, $value) {
switch ($property) {
// _queueAdapter() needs these properties.
case 'ctx':
case 'queue':
if (!$this->customUpgrader) {
throw new \RuntimeException("AutomaticUpgrader($this->extensionName): Cannot assign delegated property: $property (No custom-upgrader found)");
}
// "Invasive": unlike QueueTrait, we are not in the same class as the recipient. And we can't replace previously-published QueueTraits.
Invasive::set([$this->customUpgrader, $property], $value);
return;
}

throw new \RuntimeException("AutomaticUpgrader($this->extensionName): Cannot assign unknown property: $property");
}

public function __get($property) {
switch ($property) {
// _queueAdapter() needs these properties.
case 'ctx':
case 'queue':
if (!$this->customUpgrader) {
throw new \RuntimeException("AutomaticUpgrader($this->extensionName): Cannot read delegated property: $property (No custom-upgrader found)");
}
// "Invasive": Unlike QueueTrait, we are not in the same class as the recipient. And we can't replace previously-published QueueTraits.
return Invasive::get([$this->customUpgrader, $property]);
}
throw new \RuntimeException("AutomaticUpgrader($this->extensionName): Cannot read unknown property: $property");
}

public function __call($name, $arguments) {
if ($this->customUpgrader) {
return call_user_func_array([$this->customUpgrader, $name], $arguments);
}
else {
throw new \RuntimeException("AutomaticUpgrader($this->extensionName): Cannot delegate method $name (No custom-upgrader found)");
}
}

};
46 changes: 46 additions & 0 deletions mixin/lib/[email protected]/src/CiviMixSchema.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php
namespace CiviMix\Schema;

/**
* This object is known as $GLOBALS['CiviMixSchema']. It is a reloadable service-object.
* (It may be reloaded if you enable a new extension that includes an upgraded copy.)
*/
return new class() {

/**
* @var string
* Regular expression. Note the 2 groupings. $m[1] identifies a per-extension namespace. $m[2] identifies the actual class.
*/
private $regex = ';^CiviMix\\\Schema\\\(\w+)\\\(AutomaticUpgrader|DAO)$;';

/**
* If someone requests a class like:
*
* CiviMix\Schema\MyExt\AutomaticUpgrader
*
* then load the latest version of:
*
* civimix-schema/src/Helper.php
*/
public function loadClass(string $class) {
if (preg_match($this->regex, $class, $m)) {
$absPath = __DIR__ . DIRECTORY_SEPARATOR . $m[2] . '.php';
class_alias(get_class(require $absPath), $class);
}
}

/**
* @param string $extensionKey
* Ex: 'org.civicrm.flexmailer'
* @return \CiviMix\Schema\SchemaHelperInterface
*/
public function getHelper(string $extensionKey) {
$store = &\Civi::$statics['CiviMixSchema-helpers'];
if (!isset($store[$extensionKey])) {
$class = get_class(require __DIR__ . '/SchemaHelper.php');
$store[$extensionKey] = new $class($extensionKey);
}
return $store[$extensionKey];
}

};
Loading
Loading