platform->runPlugins($cacheCleaningEvent, $options); } } } /** * Clean a cache group on Joomla 3 * * @param string $group The cache to clean, e.g. com_content * @param int $client_id The application ID for which the cache will be cleaned * @param object $app The current CMS application. DO NOT TYPEHINT MORE SPECIFICALLY! * * @return array Cache controller options, including cleaning result * @throws Exception */ private static function clearCacheGroupJoomla3(string $group, int $client_id, object $app): array { $options = [ 'defaultgroup' => $group, 'cachebase' => ($client_id) ? self::getAppConfigParam($app, 'cache_path', JPATH_SITE . '/cache') : JPATH_ADMINISTRATOR . '/cache', 'result' => true, ]; try { $cache = Cache::getInstance('callback', $options); /** @noinspection PhpUndefinedMethodInspection Available via __call(), not tagged in Joomla core */ $cache->clean(); } catch (Throwable $e) { $options['result'] = false; } return $options; } /** * Clean a cache group on Joomla 4 * * @param string $group The cache to clean, e.g. com_content * @param int $client_id The application ID for which the cache will be cleaned * @param object $app The current CMS application. DO NOT TYPEHINT MORE SPECIFICALLY! * * @return array Cache controller options, including cleaning result * @throws Exception */ private static function clearCacheGroupJoomla4(string $group, int $client_id, object $app): array { // Get the default cache folder. Start by using the JPATH_CACHE constant. $cacheBaseDefault = JPATH_CACHE; $appClientId = 0; if (method_exists($app, 'getClientId')) { $appClientId = $app->getClientId(); } // -- If we are asked to clean cache on the other side of the application we need to find a new cache base if ($client_id != $appClientId) { $cacheBaseDefault = (($client_id) ? JPATH_SITE : JPATH_ADMINISTRATOR) . '/cache'; } // Get the cache controller's options $options = [ 'defaultgroup' => $group, 'cachebase' => self::getAppConfigParam($app, 'cache_path', $cacheBaseDefault), 'result' => true, ]; try { $container = Factory::getContainer(); if (empty($container)) { throw new \RuntimeException('Cannot get Joomla 4 application container'); } /** @var CacheControllerFactoryInterface $cacheControllerFactory */ $cacheControllerFactory = $container->get('cache.controller.factory'); if (empty($cacheControllerFactory)) { throw new \RuntimeException('Cannot get Joomla 4 cache controller factory'); } /** @var CallbackController $cache */ $cache = $cacheControllerFactory->createCacheController('callback', $options); if (empty($cache) || !property_exists($cache, 'cache') || !method_exists($cache->cache, 'clean')) { throw new \RuntimeException('Cannot get Joomla 4 cache controller'); } $cache->cache->clean(); } catch (CacheExceptionInterface $exception) { $options['result'] = false; } catch (Throwable $e) { $options['result'] = false; } return $options; } private static function getAppConfigParam(?object $app, string $key, $default = null) { /** * Any kind of Joomla CMS, Web, API or CLI application extends from AbstractApplication and has the get() * method to return application configuration parameters. */ if (is_object($app) && ($app instanceof AbstractApplication)) { return $app->get($key, $default); } /** * A custom application may instead implement the Joomla\Application\ConfigurationAwareApplicationInterface * interface (Joomla 4+), in whihc case it has the get() method to return application configuration parameters. */ if (is_object($app) && interface_exists('Joomla\Application\ConfigurationAwareApplicationInterface', true) && ($app instanceof ConfigurationAwareApplicationInterface)) { return $app->get($key, $default); } /** * A Joomla 3 custom application may simply implement the get() method without implementing an interface. */ if (is_object($app) && method_exists($app, 'get')) { return $app->get($key, $default); } /** * At this point the $app variable is not an object or is something I can't use. Does the Joomla Factory still * has the legacy static method getConfig() to get the application configuration? If so, use it. */ if (method_exists(Factory::class, 'getConfig')) { try { $jConfig = Factory::getConfig(); if (is_object($jConfig) && ($jConfig instanceof Registry)) { $jConfig->get($key, $default); } } catch (Throwable $e) { /** * Factory tries to go through the application object. It might fail if there is a custom application * which doesn't implement the interfaces Factory expects. In this case we get a Fatal Error whcih we * can trap and fall through to the next if-block. */ } } /** * When we are here all hope is nearly lost. We have to do a crude approximation of Joomla Factory's code to * create an application configuration Registry object and retrieve the configuration values. This will work as * long as the JConfig class (defined in configuration.php) has been loaded. */ $configPath = defined('JPATH_CONFIGURATION') ? JPATH_CONFIGURATION : (defined('JPATH_ROOT') ? JPATH_ROOT : null); $configPath = $configPath ?? (__DIR__ . '/../../..'); $configFile = $configPath . '/configuration.php'; if (!class_exists('JConfig') && @file_exists($configFile) && @is_file($configFile) && @is_readable($configFile)) { require_once $configFile; } if (class_exists('JConfig')) { try { $jConfig = new Registry(); $configObject = new \JConfig(); $jConfig->loadObject($configObject); return $jConfig->get($key, $default); } catch (Throwable $e) { return $default; } } /** * All hope is lost. I can't find the application configuration. I am returning the default value and hope stuff * won't break spectacularly... */ return $default; } }