diff --git a/eWAYRecurring.civix.php b/eWAYRecurring.civix.php index 1c69590..f9475fd 100644 --- a/eWAYRecurring.civix.php +++ b/eWAYRecurring.civix.php @@ -89,7 +89,6 @@ public static function schema() { use CRM_eWAYRecurring_ExtensionUtil as E; -($GLOBALS['_PathLoad'][0] ?? require __DIR__ . '/mixin/lib/pathload-0.php'); pathload()->addSearchDir(__DIR__ . '/mixin/lib'); spl_autoload_register('_eWAYRecurring_civix_class_loader', TRUE, TRUE); diff --git a/info.xml b/info.xml index a319a18..e566b36 100644 --- a/info.xml +++ b/info.xml @@ -28,8 +28,8 @@ menu-xml@1.0.0 setting-php@1.0.0 - smarty-v2@1.0.3 entity-types-php@2.0.0 + smarty@1.0.3 diff --git a/mixin/entity-types-php@2.0.0.mixin.php b/mixin/entity-types-php@2.0.0.mixin.php deleted file mode 100644 index 54616e6..0000000 --- a/mixin/entity-types-php@2.0.0.mixin.php +++ /dev/null @@ -1,40 +0,0 @@ -addListener('hook_civicrm_entityTypes', function ($e) use ($mixInfo) { - // When deactivating on a polyfill/pre-mixin system, listeners may not cleanup automatically. - if (!$mixInfo->isActive() || !is_dir($mixInfo->getPath('schema'))) { - return; - } - - $files = (array) glob($mixInfo->getPath('schema/*.entityType.php')); - foreach ($files as $file) { - $entity = include $file; - $entity['module'] = $mixInfo->longName; - $e->entityTypes[$entity['name']] = $entity; - } - }); - -}; diff --git a/mixin/lib/pathload-0.php b/mixin/lib/pathload-0.php deleted file mode 100644 index 76d6425..0000000 --- a/mixin/lib/pathload-0.php +++ /dev/null @@ -1,711 +0,0 @@ -top = $top; - } - public function offsetExists($version): bool { - return ($version === 'top' || $version <= $this->top->version); - } - public function offsetGet($version): ?\PathLoadInterface { - if ($version === 'top' || $version <= $this->top->version) { - return $this->top; - } - return NULL; - } - public function offsetSet($offset, $value): void { - error_log("Cannot overwrite PathLoad[$offset]"); - } - public function offsetUnset($offset): void { - error_log("Cannot remove PathLoad[$offset]"); - } - } - class Package { - /** - * Split a package identifier into its parts. - * - * @param string $package - * Ex: 'foobar@1.2.3' - * @return array - * Tuple: [$majorName, $name, $version] - * Ex: 'foobar@1', 'foobar', '1.2.3' - */ - public static function parseExpr(string $package): array { - if (strpos($package, '@') === FALSE) { - throw new \RuntimeException("Malformed package name: $package"); - } - [$prefix, $suffix] = explode('@', $package, 2); - $prefix = str_replace('/', '~', $prefix); - [$major] = explode('.', $suffix, 2); - return ["$prefix@$major", $prefix, $suffix]; - } - public static function parseFileType(string $file): array { - if (substr($file, -4) === '.php') { - return ['php', substr(basename($file), 0, -4)]; - } - elseif (substr($file, '-5') === '.phar') { - return ['phar', substr(basename($file), 0, -5)]; - } - elseif (is_dir($file)) { - return ['dir', basename($file)]; - } - else { - return [NULL, NULL]; - } - } - /** - * @param string $file - * Ex: '/var/www/app-1/lib/foobar@.1.2.3.phar' - * @return \PathLoad\Vn\Package|null - */ - public static function create(string $file): ?Package { - [$type, $base] = self::parseFileType($file); - if ($type === NULL) { - return NULL; - } - $self = new Package(); - [$self->majorName, $self->name, $self->version] = static::parseExpr($base); - $self->file = $file; - $self->type = $type; - return $self; - } - /** - * @var string - * Ex: '/var/www/app-1/lib/cloud-file-io@1.2.3.phar' - */ - public $file; - /** - * @var string - * Ex: 'cloud-file-io' - */ - public $name; - /** - * @var string - * Ex: 'cloud-file-io@1' - */ - public $majorName; - /** - * @var string - * Ex: '1.2.3' - */ - public $version; - /** - * @var string - * Ex: 'php' or 'phar' or 'dir' - */ - public $type; - public $reloadable = FALSE; - } - class Scanner { - /** - * @var array - * Array(string $id => [package => string, glob => string]) - * @internal - */ - public $allRules = []; - /** - * @var array - * Array(string $id => [package => string, glob => string]) - * @internal - */ - public $newRules = []; - /** - * @param array $rule - * Ex: ['package' => '*', 'glob' => '/var/www/lib/*@*'] - * Ex: ['package' => 'cloud-file-io@1', 'glob' => '/var/www/lib/cloud-io@1*.phar']) - * @return void - */ - public function addRule(array $rule): void { - $id = static::id($rule); - $this->newRules[$id] = $this->allRules[$id] = $rule; - } - public function reset(): void { - $this->newRules = $this->allRules; - } - /** - * Evaluate any rules that have a chance of finding $packageHint. - * - * @param string $packageHint - * Give a hint about what package we're looking for. - * The scanner will try to target packages based on this hint. - * Ex: '*' or 'cloud-file-io' - * @return \Generator - * A list of packages. These may not be the exact package you're looking for. - * You should assimilate knowledge of all outputs because you may not get them again. - */ - public function scan(string $packageHint): \Generator { - yield from []; - foreach (array_keys($this->newRules) as $id) { - $searchRule = $this->newRules[$id]; - if ($searchRule['package'] === '*' || $searchRule['package'] === $packageHint) { - unset($this->newRules[$id]); - if (isset($searchRule['glob'])) { - foreach ((array) glob($searchRule['glob']) as $file) { - if (($package = Package::create($file)) !== NULL) { - yield $package; - } - } - } - if (isset($searchRule['file'])) { - $package = new Package(); - $package->file = $searchRule['file']; - $package->name = $searchRule['package']; - $package->majorName = $searchRule['package'] . '@' . explode('.', $searchRule['version'])[0]; - $package->version = $searchRule['version']; - $package->type = $searchRule['type'] ?: Package::parseFileType($searchRule['file'])[0]; - yield $package; - } - } - } - } - protected static function id(array $rule): string { - if (isset($rule['glob'])) { - return $rule['glob']; - } - elseif (isset($rule['file'])) { - return md5(implode(' ', [$rule['file'], $rule['package'], $rule['version']])); - } - else { - throw new \RuntimeException("Cannot identify rule: " . json_encode($rule)); - } - } - } - class Psr0Loader { - /** - * @var array - * Ex: $paths['F']['Foo_'][0] = '/var/www/app/lib/foo@1.0.0/src/'; - * @internal - */ - public $paths = []; - /** - * @param string $dir - * @param array $config - * Ex: ['Foo_' => ['src/']] or ['Foo_' => ['Foo_']] - */ - public function addAll(string $dir, array $config) { - $dir = rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; - foreach ($config as $prefix => $relPaths) { - $bucket = $prefix[0]; - foreach ((array) $relPaths as $relPath) { - $this->paths[$bucket][$prefix][] = $dir . $relPath; - } - } - } - /** - * Loads the class file for a given class name. - * - * @param string $class The fully-qualified class name. - * @return mixed The mapped file name on success, or boolean false on failure. - */ - public function loadClass(string $class) { - $bucket = $class[0]; - if (!isset($this->paths[$bucket])) { - return FALSE; - } - $file = DIRECTORY_SEPARATOR . str_replace(['_', '\\'], [DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR], $class) . '.php'; - foreach ($this->paths[$bucket] as $prefix => $paths) { - if ($prefix === substr($class, 0, strlen($prefix))) { - foreach ($paths as $path) { - $fullFile = $path . $file; - if (file_exists($fullFile)) { - doRequire($fullFile); - return $fullFile; - } - } - } - } - return FALSE; - } - } - class Psr4Loader { - /** - * @var array - * Ex: $prefixes['Foo\\'][0] = '/var/www/app/lib/foo@1.0.0/src/'] - * @internal - */ - public $prefixes = []; - public function addAll(string $dir, array $config) { - foreach ($config as $prefix => $relPaths) { - foreach ($relPaths as $relPath) { - $this->addNamespace($prefix, $dir . '/' . $relPath); - } - } - } - /** - * Adds a base directory for a namespace prefix. - * - * @param string $prefix - * The namespace prefix. - * @param string $baseDir - * A base directory for class files in the namespace. - * @return void - */ - private function addNamespace($prefix, $baseDir) { - $prefix = trim($prefix, '\\') . '\\'; - $baseDir = rtrim($baseDir, DIRECTORY_SEPARATOR) . '/'; - if (isset($this->prefixes[$prefix]) === FALSE) { - $this->prefixes[$prefix] = []; - } - array_push($this->prefixes[$prefix], $baseDir); - } - /** - * Loads the class file for a given class name. - * - * @param string $class The fully-qualified class name. - * @return mixed The mapped file name on success, or boolean false on failure. - */ - public function loadClass(string $class) { - $prefix = $class; - while (FALSE !== $pos = strrpos($prefix, '\\')) { - $prefix = substr($class, 0, $pos + 1); - $relativeClass = substr($class, $pos + 1); - if ($mappedFile = $this->findRelativeClass($prefix, $relativeClass)) { - doRequire($mappedFile); - return $mappedFile; - } - $prefix = rtrim($prefix, '\\'); - } - return FALSE; - } - /** - * Load the mapped file for a namespace prefix and relative class. - * - * @param string $prefix - * The namespace prefix. - * @param string $relativeClass - * The relative class name. - * @return string|FALSE - * Matched file name, or FALSE if none found. - */ - private function findRelativeClass($prefix, $relativeClass) { - if (isset($this->prefixes[$prefix]) === FALSE) { - return FALSE; - } - $relFile = str_replace('\\', DIRECTORY_SEPARATOR, $relativeClass) . '.php'; - foreach ($this->prefixes[$prefix] as $baseDir) { - $file = $baseDir . $relFile; - if (file_exists($file)) { - return $file; - } - } - return FALSE; - } - } - class PathLoad implements \PathLoadInterface { - /** - * @var null|int - */ - public $version; - /** - * @var Scanner - * @internal - */ - public $scanner; - /** - * List of best-known versions for each package. - * - * Packages are loaded lazily. Once loaded, the data is moved to $loadedPackages. - * - * @var Package[] - * Ex: ['cloud-file-io@1' => new Package('/usr/share/php-pathload/cloud-file-io@1.2.3.phar', - * ...)] - * @internal - */ - public $availablePackages = []; - /** - * List of packages that have already been resolved. - * - * @var Package[] - * Ex: ['cloud-file-io@1' => new Package('/usr/share/php-pathload/cloud-file-io@1.2.3.phar', - * ...)] Note: If PathLoad version is super-ceded, then the loadedPackages may be instances of - * an old `Package` class. Be mindful of duck-type compatibility. We don't strictly need to - * retain this data, but it feels it'd be handy for debugging. - * @internal - */ - public $loadedPackages = []; - /** - * Log of package activations. Used to re-initialize class-loader if we upgrade. - * - * @var array - * @internal - */ - public $activatedPackages = []; - /** - * List of hints for class-loading. If someone tries to use a matching class, then - * load the corresponding package. - * - * Namespace-rules are evaluated lazily. Once evaluated, the data is removed. - * - * @var array - * Array(string $prefix => [string $package => string $package]) - * Ex: ['Super\Cloud\IO\' => ['cloud-io@1' => 'cloud-io@1'] - * @internal - */ - public $availableNamespaces; - /** - * @var \PathLoad\Vn\Psr0Loader - * @internal - */ - public $psr0; - /** - * @var \PathLoad\Vn\Psr4Loader - * @internal - */ - public $psr4; - /** - * @param int $version - * Identify the version being instantiated. - * @param \PathLoadInterface|null $old - * If this instance is a replacement for an older instance, then it will be passed in. - * @return \ArrayAccess - * Versioned work-a-like array. - */ - public static function create(int $version, ?\PathLoadInterface $old = NULL) { - if ($old !== NULL) { - $old->unregister(); - } - $new = new static(); - $new->version = $version; - $new->scanner = new Scanner(); - $new->psr0 = new Psr0Loader(); - $new->psr4 = new Psr4Loader(); - $new->register(); - // The exact protocol for assimilating $old instances may need change. - // This seems like a fair guess as long as old properties are forward-compatible. - - if ($old === NULL) { - $baseDirs = getenv('PHP_PATHLOAD') ? explode(PATH_SEPARATOR, getenv('PHP_PATHLOAD')) : []; - foreach ($baseDirs as $baseDir) { - $new->addSearchDir($baseDir); - } - } - else { - // TIP: You might use $old->version to decide what to use. - foreach ($old->scanner->allRules as $rule) { - $new->scanner->addRule($rule); - } - $new->loadedPackages = $old->loadedPackages; - $new->availableNamespaces = $old->availableNamespaces; - foreach ($old->activatedPackages as $activatedPackage) { - $new->activatePackage($activatedPackage['name'], $activatedPackage['dir'], $activatedPackage['config']); - } - } - return new Versions($new); - } - public function register(): \PathLoadInterface { - spl_autoload_register([$this, 'loadClass']); - return $this; - } - public function unregister(): \PathLoadInterface { - spl_autoload_unregister([$this, 'loadClass']); - return $this; - } - public function reset(): \PathLoadInterface { - $this->scanner->reset(); - return $this; - } - /** - * Append a directory (with many packages) to the search-path. - * - * @param string $baseDir - * The path to a base directory (e.g. `/var/www/myapp/lib`) which contains many packages (e.g. - * `foo@1.2.3.phar` or `bar@4.5.6/autoload.php`). - */ - public function addSearchDir(string $baseDir): \PathLoadInterface { - $this->scanner->addRule(['package' => '*', 'glob' => "$baseDir/*@*"]); - return $this; - } - /** - * Append one specific item to the search list. - * - * @param string $name - * Ex: 'cloud-file-io' - * @param string $version - * Ex: '1.2.3' - * @param string $file - * Full path to the file or folder. - * @param string|null $type - * One of: 'php', 'phar', or 'dir'. NULL will auto-detect. - * - * @return \PathLoadInterface - */ - public function addSearchItem(string $name, string $version, string $file, ?string $type = NULL): \PathLoadInterface { - $this->scanner->addRule(['package' => $name, 'version' => $version, 'file' => $file, 'type' => $type]); - return $this; - } - /** - * Add auto-loading hints. If someone requests a class in $namespace, then we load $package. - * - * Consecutive/identical calls to addNamespace() are de-duplicated. - * - * @param string $package - * Ex: 'cloud-io@1' - * @param string|string[] $namespaces - * Ex: 'Super\Cloud\IO\' - */ - public function addNamespace(string $package, $namespaces): \PathLoadInterface { - foreach ((array) $namespaces as $namespace) { - $this->availableNamespaces[$namespace][$package] = $package; - } - return $this; - } - public function loadClass(string $class) { - if (strpos($class, '\\') !== FALSE) { - $this->loadPackagesByNamespace('\\', explode('\\', $class)); - } - elseif (strpos($class, '_') !== FALSE) { - $this->loadPackagesByNamespace('_', explode('_', $class)); - } - return $this->psr4->loadClass($class) || $this->psr0->loadClass($class); - } - /** - * If the application requests class "Foo\Bar\Whiz\Bang", then you should load - * any packages related to "Foo\*", "Foo\Bar\*", or "Foo\Bar\Whiz\*". - * - * @param string $delim - * Ex: '\\' or '_' - * @param string[] $classParts - * Ex: ['Symfony', 'Components', 'Filesystem', 'Filesystem'] - */ - private function loadPackagesByNamespace(string $delim, array $classParts): void { - array_pop($classParts); - do { - $foundPackages = FALSE; - $namespace = ''; - foreach ($classParts as $nsPart) { - $namespace .= $nsPart . $delim; - if (isset($this->availableNamespaces[$namespace])) { - $packages = $this->availableNamespaces[$namespace]; - foreach ($packages as $package) { - unset($this->availableNamespaces[$namespace][$package]); - if ($this->loadPackage($package)) { - $foundPackages = TRUE; - } - else { - trigger_error("PathLoad: Failed to locate package \"$package\" required for namespace \"$namespace\"", E_USER_WARNING); - $this->availableNamespaces[$namespace][$package] = $package; /* Maybe some other time */ - } - } - } - } - } while ($foundPackages); - // Loading a package could produce metadata about other packages. Assimilate those too. - } - /** - * Load the content of a package. - * - * @param string $majorName - * Ex: 'cloud-io@1' - * @param bool $reload - * @return string|NULL - * The version# of the loaded package. Otherwise, NULL - */ - public function loadPackage(string $majorName, bool $reload = FALSE): ?string { - if (isset($this->loadedPackages[$majorName])) { - if ($reload && $this->loadedPackages[$majorName]->reloadable) { - $this->scanner->reset(); - } - else { - if ($reload) { - trigger_error("PathLoad: Declined to reload \"$majorName\". Package is not reloadable.", E_USER_WARNING); - } - return $this->loadedPackages[$majorName]->version; - } - } - $this->scanAvailablePackages(explode('@', $majorName, 2)[0], $this->availablePackages); - if (!isset($this->availablePackages[$majorName])) { - return NULL; - } - $package = $this->loadedPackages[$majorName] = $this->availablePackages[$majorName]; - unset($this->availablePackages[$majorName]); - switch ($package->type ?? NULL) { - case 'php': - doRequire($package->file); - return $package->version; - case 'phar': - doRequire($package->file); - $this->useMetadataFiles($package, 'phar://' . $package->file); - return $package->version; - case 'dir': - $this->useMetadataFiles($package, $package->file); - return $package->version; - default: - \error_log("PathLoad: Package (\"$majorName\") appears malformed."); - return NULL; - } - } - private function scanAvailablePackages(string $hint, array &$avail): void { - foreach ($this->scanner->scan($hint) as $package) { - /** @var Package $package */ - if (!isset($avail[$package->majorName]) || \version_compare($package->version, $avail[$package->majorName]->version, '>')) { - $avail[$package->majorName] = $package; - } - } - } - /** - * When loading a package, execute metadata files like "pathload.main.php" or "pathload.json". - * - * @param Package $package - * @param string $dir - * Ex: '/var/www/lib/cloud-io@1.2.0' - * Ex: 'phar:///var/www/lib/cloud-io@1.2.0.phar' - */ - private function useMetadataFiles(Package $package, string $dir): void { - $phpFile = "$dir/pathload.main.php"; - $jsonFile = "$dir/pathload.json"; - if (file_exists($phpFile)) { - require $phpFile; - } - elseif (file_exists($jsonFile)) { - $jsonData = json_decode(file_get_contents($jsonFile), TRUE); - $id = $package->name . '@' . $package->version; - $this->activatePackage($id, $dir, $jsonData); - } - } - /** - * Given a configuration for the package, activate the correspond autoloader rules. - * - * @param string $majorName - * Ex: 'cloud-io@1' - * @param string|null $dir - * Used for applying the 'autoload' rules. - * Ex: '/var/www/lib/cloud-io@1.2.3' - * @param array $config - * Ex: ['autoload' => ['psr4' => ...], 'require-namespace' => [...], 'require-package' => [...]] - * @return \PathLoadInterface - */ - public function activatePackage(string $majorName, ?string $dir, array $config): \PathLoadInterface { - if (isset($config['reloadable'])) { - $this->loadedPackages[$majorName]->reloadable = $config['reloadable']; - } - if (!isset($config['autoload'])) { - return $this; - } - if ($dir === NULL) { - throw new \RuntimeException("Cannot activate package $majorName. The 'autoload' property requires a base-directory."); - } - $this->activatedPackages[] = ['name' => $majorName, 'dir' => $dir, 'config' => $config]; - if (!empty($config['autoload']['include'])) { - foreach ($config['autoload']['include'] as $file) { - doRequire($dir . DIRECTORY_SEPARATOR . $file); - } - } - if (isset($config['autoload']['psr-0'])) { - $this->psr0->addAll($dir, $config['autoload']['psr-0']); - } - if (isset($config['autoload']['psr-4'])) { - $this->psr4->addAll($dir, $config['autoload']['psr-4']); - } - foreach ($config['require-namespace'] ?? [] as $nsRule) { - foreach ((array) $nsRule['package'] as $package) { - foreach ((array) $nsRule['prefix'] as $prefix) { - $this->availableNamespaces[$prefix][$package] = $package; - } - } - } - foreach ($config['require-package'] ?? [] as $package) { - $this->loadPackage($package); - } - return $this; - } - } - } -} - -namespace { - // New or upgraded instance. - $GLOBALS['_PathLoad'] = \PathLoad\V0\PathLoad::create(0, $GLOBALS['_PathLoad']['top'] ?? NULL); - if (!function_exists('pathload')) { - /** - * Get a reference the PathLoad manager. - * - * @param int|string $version - * @return \PathLoadInterface - */ - function pathload($version = 'top') { - return $GLOBALS['_PathLoad'][$version]; - } - } - return pathload(); -} diff --git a/mixin/smarty-v2@1.0.3.mixin.php b/mixin/smarty-v2@1.0.3.mixin.php deleted file mode 100644 index f8718c8..0000000 --- a/mixin/smarty-v2@1.0.3.mixin.php +++ /dev/null @@ -1,78 +0,0 @@ -getPath('templates'); - if (!file_exists($dir)) { - return; - } - - $register = function($newDirs) { - $smarty = CRM_Core_Smarty::singleton(); - $v2 = isset($smarty->_version) && version_compare($smarty->_version, 3, '<'); - $templateDirs = (array) ($v2 ? $smarty->template_dir : $smarty->getTemplateDir()); - $templateDirs = array_merge($newDirs, $templateDirs); - $templateDirs = array_unique(array_map(function($v) { - $v = str_replace(DIRECTORY_SEPARATOR, '/', $v); - $v = rtrim($v, '/') . '/'; - return $v; - }, $templateDirs)); - if ($v2) { - $smarty->template_dir = $templateDirs; - } - else { - $smarty->setTemplateDir($templateDirs); - } - }; - - // Let's figure out what environment we're in -- so that we know the best way to call $register(). - - if (!empty($GLOBALS['_CIVIX_MIXIN_POLYFILL'])) { - // Polyfill Loader (v<=5.45): We're already in the middle of firing `hook_config`. - if ($mixInfo->isActive()) { - $register([$dir]); - } - return; - } - - if (CRM_Extension_System::singleton()->getManager()->extensionIsBeingInstalledOrEnabled($mixInfo->longName)) { - // New Install, Standard Loader: The extension has just been enabled, and we're now setting it up. - // System has already booted. New templates may be needed for upcoming installation steps. - $register([$dir]); - return; - } - - // Typical Pageview, Standard Loader: Defer the actual registration for a moment -- to ensure that Smarty is online. - // We need to bundle-up all dirs -- Smarty 3/4/5 is inefficient with processing repeated calls to `getTemplateDir()`+`setTemplateDir()` - if (!isset(Civi::$statics[__FILE__]['event'])) { - Civi::$statics[__FILE__]['event'] = 'civi.smarty-v2.addPaths.' . md5(__FILE__); - Civi::dispatcher()->addListener('hook_civicrm_config', function() use ($register) { - $dirs = []; - $event = \Civi\Core\Event\GenericHookEvent::create(['dirs' => &$dirs]); - Civi::dispatcher()->dispatch(Civi::$statics[__FILE__]['event'], $event); - $register($dirs); - }); - } - - Civi::dispatcher()->addListener(Civi::$statics[__FILE__]['event'], function($event) use ($mixInfo, $dir) { - if ($mixInfo->isActive()) { - array_unshift($event->dirs, $dir); - } - }); - -};