Current File : /home/pacjaorg/public_html/kmm/libraries/src/Extension/ExtensionManagerTrait.php |
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Extension;
use Joomla\CMS\Dispatcher\ModuleDispatcherFactory;
use Joomla\CMS\Event\AbstractEvent;
use Joomla\CMS\Helper\HelperFactory;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\Exception\ContainerNotFoundException;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('JPATH_PLATFORM') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Trait for classes which can load extensions
*
* @since 4.0.0
*/
trait ExtensionManagerTrait
{
/**
* Boots the component with the given name.
*
* @param string $component The component to boot.
*
* @return ComponentInterface
*
* @since 4.0.0
*/
public function bootComponent($component): ComponentInterface
{
// Normalize the component name
$component = strtolower($component);
$component = str_starts_with($component, 'com_') ? substr($component, 4) : $component;
// Path to look for services
$path = JPATH_ADMINISTRATOR . '/components/com_' . $component;
return $this->loadExtension(ComponentInterface::class, $component, $path);
}
/**
* Boots the module with the given name.
*
* @param string $module The module to boot
* @param string $applicationName The application name
*
* @return ModuleInterface
*
* @since 4.0.0
*/
public function bootModule($module, $applicationName): ModuleInterface
{
// Normalize the module name
$module = strtolower($module);
$module = str_starts_with($module, 'mod_') ? substr($module, 4) : $module;
// Path to look for services
$path = JPATH_SITE . '/modules/mod_' . $module;
if ($applicationName === 'administrator') {
$path = JPATH_ADMINISTRATOR . '/modules/mod_' . $module;
}
return $this->loadExtension(ModuleInterface::class, $module, $path);
}
/**
* Boots the plugin with the given name and type.
*
* @param string $plugin The plugin name
* @param string $type The type of the plugin
*
* @return PluginInterface
*
* @since 4.0.0
*/
public function bootPlugin($plugin, $type): PluginInterface
{
// Normalize the plugin name
$plugin = strtolower($plugin);
$plugin = str_starts_with($plugin, 'plg_') ? substr($plugin, 4) : $plugin;
// Path to look for services
$path = JPATH_SITE . '/plugins/' . $type . '/' . $plugin;
return $this->loadExtension(PluginInterface::class, $plugin . ':' . $type, $path);
}
/**
* Loads the extension.
*
* @param string $type The extension type
* @param string $extensionName The extension name
* @param string $extensionPath The path of the extension
*
* @return ComponentInterface|ModuleInterface|PluginInterface
*
* @since 4.0.0
*/
private function loadExtension($type, $extensionName, $extensionPath)
{
// Check if the extension is already loaded
if (!empty(ExtensionHelper::$extensions[$type][$extensionName])) {
return ExtensionHelper::$extensions[$type][$extensionName];
}
// The container to get the services from
$container = $this->getContainer()->createChild();
$container->get(DispatcherInterface::class)->dispatch(
'onBeforeExtensionBoot',
AbstractEvent::create(
'onBeforeExtensionBoot',
[
'subject' => $this,
'type' => $type,
'extensionName' => $extensionName,
'container' => $container,
]
)
);
// The path of the loader file
$path = $extensionPath . '/services/provider.php';
if (is_file($path)) {
// Load the file
$provider = require_once $path;
// Check if the extension supports the service provider interface
if ($provider instanceof ServiceProviderInterface) {
$provider->register($container);
}
}
// Fallback to legacy
if (!$container->has($type)) {
switch ($type) {
case ComponentInterface::class:
$container->set($type, new LegacyComponent('com_' . $extensionName));
break;
case ModuleInterface::class:
$container->set($type, new Module(new ModuleDispatcherFactory(''), new HelperFactory('')));
break;
case PluginInterface::class:
list($pluginName, $pluginType) = explode(':', $extensionName);
$container->set($type, $this->loadPluginFromFilesystem($pluginName, $pluginType));
}
}
$container->get(DispatcherInterface::class)->dispatch(
'onAfterExtensionBoot',
AbstractEvent::create(
'onAfterExtensionBoot',
[
'subject' => $this,
'type' => $type,
'extensionName' => $extensionName,
'container' => $container,
]
)
);
$extension = $container->get($type);
if ($extension instanceof BootableExtensionInterface) {
$extension->boot($container);
}
// Cache the extension
ExtensionHelper::$extensions[$type][$extensionName] = $extension;
return $extension;
}
/**
* Creates a CMS plugin from the filesystem.
*
* @param string $plugin The plugin
* @param string $type The type
*
* @return CMSPlugin
*
* @since 4.0.0
*/
private function loadPluginFromFilesystem(string $plugin, string $type)
{
// The dispatcher
$dispatcher = $this->getContainer()->get(DispatcherInterface::class);
// Clear the names
$plugin = preg_replace('/[^A-Z0-9_\.-]/i', '', $plugin);
$type = preg_replace('/[^A-Z0-9_\.-]/i', '', $type);
// The path of the plugin
$path = JPATH_PLUGINS . '/' . $type . '/' . $plugin . '/' . $plugin . '.php';
// Return an empty class when the file doesn't exist
if (!is_file($path)) {
return new DummyPlugin($dispatcher);
}
// Include the file of the plugin
require_once $path;
// Compile the classname
$className = 'Plg' . str_replace('-', '', $type) . $plugin;
// Editors don't follow the convention
if ($type === 'editors') {
$className = 'PlgEditor' . ucfirst($plugin);
}
// Editor buttons don't follow the convention
if ($type === 'editors-xtd') {
$className = 'PlgEditorsXtd' . $plugin;
if (!class_exists($className)) {
$className = 'PlgButton' . $plugin;
}
}
// Return an empty class when the class doesn't exist
if (!class_exists($className)) {
return new DummyPlugin($dispatcher);
}
// Instantiate the plugin
return new $className($dispatcher, (array) PluginHelper::getPlugin($type, $plugin));
}
/**
* Get the DI container.
*
* @return Container
*
* @since 4.0.0
* @throws ContainerNotFoundException May be thrown if the container has not been set.
*/
abstract protected function getContainer();
}