Current File : /home/pacjaorg/public_html/km/libraries/src/Application/ConsoleApplication.php |
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Application;
use Joomla\CMS\Console;
use Joomla\CMS\Extension\ExtensionManagerTrait;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Language;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Router\Router;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Version;
use Joomla\Console\Application;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\DI\Container;
use Joomla\DI\ContainerAwareTrait;
use Joomla\Event\DispatcherAwareInterface;
use Joomla\Event\DispatcherAwareTrait;
use Joomla\Event\DispatcherInterface;
use Joomla\Input\Input;
use Joomla\Registry\Registry;
use Joomla\Session\SessionInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
// phpcs:disable PSR1.Files.SideEffects
\defined('JPATH_PLATFORM') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The Joomla! CMS Console Application
*
* @since 4.0.0
*/
class ConsoleApplication extends Application implements DispatcherAwareInterface, CMSApplicationInterface
{
use DispatcherAwareTrait;
use EventAware;
use IdentityAware;
use ContainerAwareTrait;
use ExtensionManagerTrait;
use ExtensionNamespaceMapper;
use DatabaseAwareTrait;
/**
* The input.
*
* @var Input
* @since 4.0.0
*/
protected $input = null;
/**
* The name of the application.
*
* @var string
* @since 4.0.0
*/
protected $name = null;
/**
* The application language object.
*
* @var Language
* @since 4.0.0
*/
protected $language;
/**
* The application message queue.
*
* @var array
* @since 4.0.0
*/
private $messages = [];
/**
* The application session object.
*
* @var SessionInterface
* @since 4.0.0
*/
private $session;
/**
* Class constructor.
*
* @param Registry $config An optional argument to provide dependency injection for the application's config object. If the
* argument is a Registry object that object will become the application's config object,
* otherwise a default config object is created.
* @param DispatcherInterface $dispatcher An optional argument to provide dependency injection for the application's event dispatcher. If the
* argument is a DispatcherInterface object that object will become the application's event dispatcher,
* if it is null then the default event dispatcher will be created based on the application's
* loadDispatcher() method.
* @param Container $container Dependency injection container.
* @param Language $language The language object provisioned for the application.
* @param InputInterface|null $input An optional argument to provide dependency injection for the application's input object. If the
* argument is an InputInterface object that object will become the application's input object,
* otherwise a default input object is created.
* @param OutputInterface|null $output An optional argument to provide dependency injection for the application's output object. If the
* argument is an OutputInterface object that object will become the application's output object,
* otherwise a default output object is created.
*
* @since 4.0.0
*/
public function __construct(
Registry $config,
DispatcherInterface $dispatcher,
Container $container,
Language $language,
?InputInterface $input = null,
?OutputInterface $output = null
) {
// Close the application if it is not executed from the command line.
if (!\defined('STDOUT') || !\defined('STDIN') || !isset($_SERVER['argv'])) {
$this->close();
}
// Set up a Input object for Controllers etc to use
$this->input = new \Joomla\CMS\Input\Cli();
$this->language = $language;
parent::__construct($input, $output, $config);
$this->setVersion(JVERSION);
// Register the client name as cli
$this->name = 'cli';
$this->setContainer($container);
$this->setDispatcher($dispatcher);
// Set the execution datetime and timestamp;
$this->set('execution.datetime', gmdate('Y-m-d H:i:s'));
$this->set('execution.timestamp', time());
$this->set('execution.microtimestamp', microtime(true));
// Set the current directory.
$this->set('cwd', getcwd());
// Set up the environment
$this->input->set('format', 'cli');
}
/**
* Magic method to access properties of the application.
*
* @param string $name The name of the property.
*
* @return mixed A value if the property name is valid, null otherwise.
*
* @since 4.0.0
*
* @deprecated 4.0 will be removed in 6.0
* This is a B/C proxy for deprecated read accesses, use getInput() method instead
* Example:
* $app->getInput();
*/
public function __get($name)
{
switch ($name) {
case 'input':
@trigger_error(
'Accessing the input property of the application is deprecated, use the getInput() method instead.',
E_USER_DEPRECATED
);
return $this->getInput();
default:
$trace = debug_backtrace();
trigger_error(
sprintf(
'Undefined property via __get(): %1$s in %2$s on line %3$s',
$name,
$trace[0]['file'],
$trace[0]['line']
),
E_USER_NOTICE
);
}
}
/**
* Method to run the application routines.
*
* @return integer The exit code for the application
*
* @since 4.0.0
* @throws \Throwable
*/
protected function doExecute(): int
{
$exitCode = parent::doExecute();
$style = new SymfonyStyle($this->getConsoleInput(), $this->getConsoleOutput());
$methodMap = [
self::MSG_ALERT => 'error',
self::MSG_CRITICAL => 'caution',
self::MSG_DEBUG => 'comment',
self::MSG_EMERGENCY => 'caution',
self::MSG_ERROR => 'error',
self::MSG_INFO => 'note',
self::MSG_NOTICE => 'note',
self::MSG_WARNING => 'warning',
];
// Output any enqueued messages before the app exits
foreach ($this->getMessageQueue() as $type => $messages) {
$method = $methodMap[$type] ?? 'comment';
$style->$method($messages);
}
return $exitCode;
}
/**
* Execute the application.
*
* @return void
*
* @since 4.0.0
* @throws \Throwable
*/
public function execute()
{
// Load extension namespaces
$this->createExtensionNamespaceMap();
/**
* Address issues with instantiating WebApplication descendants under CLI.
*
* IMPORTANT! This code must be always be executed **before** the first use of
* PluginHelper::importPlugin(). Some plugins will attempt to register an MVCFactory for a
* component in their service provider. This will in turn try to get the SiteRouter service
* for the component which tries to get an instance of SiteApplication which will fail with
* a RuntimeException if the populateHttpHost() method has not already executed.
*/
$this->populateHttpHost();
// Import CMS plugin groups to be able to subscribe to events
PluginHelper::importPlugin('system');
PluginHelper::importPlugin('console');
parent::execute();
}
/**
* Enqueue a system message.
*
* @param string $msg The message to enqueue.
* @param string $type The message type.
*
* @return void
*
* @since 4.0.0
*/
public function enqueueMessage($msg, $type = self::MSG_INFO)
{
if (!array_key_exists($type, $this->messages)) {
$this->messages[$type] = [];
}
$this->messages[$type][] = $msg;
}
/**
* Gets the name of the current running application.
*
* @return string The name of the application.
*
* @since 4.0.0
*/
public function getName(): string
{
return $this->name;
}
/**
* Get the commands which should be registered by default to the application.
*
* @return \Joomla\Console\Command\AbstractCommand[]
*
* @since 4.0.0
*/
protected function getDefaultCommands(): array
{
return array_merge(
parent::getDefaultCommands(),
[
new Console\CleanCacheCommand(),
new Console\CheckUpdatesCommand(),
new Console\RemoveOldFilesCommand(),
new Console\AddUserCommand($this->getDatabase()),
new Console\AddUserToGroupCommand($this->getDatabase()),
new Console\RemoveUserFromGroupCommand($this->getDatabase()),
new Console\DeleteUserCommand($this->getDatabase()),
new Console\ChangeUserPasswordCommand(),
new Console\ListUserCommand($this->getDatabase()),
]
);
}
/**
* Retrieve the application configuration object.
*
* @return Registry
*
* @since 4.0.0
*/
public function getConfig()
{
return $this->config;
}
/**
* Method to get the application input object.
*
* @return Input
*
* @since 4.0.0
*/
public function getInput(): Input
{
return $this->input;
}
/**
* Method to get the application language object.
*
* @return Language The language object
*
* @since 4.0.0
*/
public function getLanguage()
{
return $this->language;
}
/**
* Get the system message queue.
*
* @return array The system message queue.
*
* @since 4.0.0
*/
public function getMessageQueue()
{
return $this->messages;
}
/**
* Method to get the application session object.
*
* @return SessionInterface The session object
*
* @since 4.0.0
*/
public function getSession()
{
return $this->session;
}
/**
* Check the client interface by name.
*
* @param string $identifier String identifier for the application interface
*
* @return boolean True if this application is of the given type client interface.
*
* @since 4.0.0
*/
public function isClient($identifier)
{
return $this->getName() === $identifier;
}
/**
* Flag if the application instance is a CLI or web based application.
*
* Helper function, you should use the native PHP functions to detect if it is a CLI application.
*
* @return boolean
*
* @since 4.0.0
*
* @deprecated 4.0 will be removed in 6.0
* Will be removed without replacement. CLI will be handled by the joomla/console package instead
*/
public function isCli()
{
return true;
}
/**
* Sets the session for the application to use, if required.
*
* @param SessionInterface $session A session object.
*
* @return $this
*
* @since 4.0.0
*/
public function setSession(SessionInterface $session): self
{
$this->session = $session;
return $this;
}
/**
* Flush the media version to refresh versionable assets
*
* @return void
*
* @since 4.0.0
*/
public function flushAssets()
{
(new Version())->refreshMediaVersion();
}
/**
* Get the long version string for the application.
*
* Overrides the parent method due to conflicting use of the getName method between the console application and
* the CMS application interface.
*
* @return string
*
* @since 4.0.0
*/
public function getLongVersion(): string
{
return sprintf('Joomla! <info>%s</info> (debug: %s)', (new Version())->getShortVersion(), (\defined('JDEBUG') && JDEBUG ? 'Yes' : 'No'));
}
/**
* Set the name of the application.
*
* @param string $name The new application name.
*
* @return void
*
* @since 4.0.0
* @throws \RuntimeException because the application name cannot be changed
*/
public function setName(string $name): void
{
throw new \RuntimeException('The console application name cannot be changed');
}
/**
* Returns the application Router object.
*
* @param string $name The name of the application.
* @param array $options An optional associative array of configuration settings.
*
* @return Router
*
* @since 4.0.6
*
* @throws \InvalidArgumentException
*
* @deprecated 4.3 will be removed in 6.0
* Inject the router or load it from the dependency injection container
* Example: Factory::getContainer()->get(ApiRouter::class);
*/
public static function getRouter($name = null, array $options = [])
{
if (empty($name)) {
throw new \InvalidArgumentException('A router name must be set in console application.');
}
$options['mode'] = Factory::getApplication()->get('sef');
return Router::getInstance($name, $options);
}
/**
* Populates the HTTP_HOST and REQUEST_URI from the URL provided in the --live-site parameter.
*
* If the URL provided is empty or invalid we will use the URL
* https://joomla.invalid/set/by/console/application just so that the CLI application doesn't
* crash when a WebApplication descendant is instantiated in it.
*
* This is a practical workaround for using any service depending on a WebApplication
* descendant under CLI.
*
* Practical example: using a component's MVCFactory which instantiates the SiteRouter
* service for that component which in turn relies on an instance of SiteApplication.
*
* @return void
* @since 4.2.1
* @see https://github.com/joomla/joomla-cms/issues/38518
*/
protected function populateHttpHost()
{
// First check for the --live-site command line option.
$input = $this->getConsoleInput();
$liveSite = '';
if ($input->hasParameterOption(['--live-site', false])) {
$liveSite = $input->getParameterOption(['--live-site'], '');
}
// Fallback to the $live_site global configuration option in configuration.php
$liveSite = $liveSite ?: $this->get('live_site', 'https://joomla.invalid/set/by/console/application');
/**
* Try to use the live site URL we were given. If all else fails, fall back to
* https://joomla.invalid/set/by/console/application.
*/
try {
$uri = Uri::getInstance($liveSite);
} catch (\RuntimeException $e) {
$uri = Uri::getInstance('https://joomla.invalid/set/by/console/application');
}
/**
* Yes, this is icky but it is the only way to trick WebApplication into compliance.
*
* @see \Joomla\Application\AbstractWebApplication::detectRequestUri
*/
$_SERVER['HTTP_HOST'] = $uri->toString(['host', 'port']);
$_SERVER['REQUEST_URI'] = $uri->getPath();
$_SERVER['HTTPS'] = $uri->getScheme() === 'https' ? 'on' : 'off';
}
/**
* Builds the default input definition.
*
* @return InputDefinition
*
* @since 4.2.1
*/
protected function getDefaultInputDefinition(): InputDefinition
{
return new InputDefinition(
[
new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
new InputOption(
'--live-site',
null,
InputOption::VALUE_OPTIONAL,
'The URL to your site, e.g. https://www.example.com'
),
new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display the help information'),
new InputOption(
'--quiet',
'-q',
InputOption::VALUE_NONE,
'Flag indicating that all output should be silenced'
),
new InputOption(
'--verbose',
'-v|vv|vvv',
InputOption::VALUE_NONE,
'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'
),
new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Displays the application version'),
new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'),
new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'),
new InputOption(
'--no-interaction',
'-n',
InputOption::VALUE_NONE,
'Flag to disable interacting with the user'
),
]
);
}
/**
* Gets a user state.
*
* @param string $key The path of the state.
* @param mixed $default Optional default value, returned if the internal value is null.
*
* @return mixed The user state or null.
*
* @since 4.4.0
*/
public function getUserState($key, $default = null)
{
$registry = $this->getSession()->get('registry');
if ($registry !== null) {
return $registry->get($key, $default);
}
return $default;
}
/**
* Gets the value of a user state variable.
*
* @param string $key The key of the user state variable.
* @param string $request The name of the variable passed in a request.
* @param string $default The default value for the variable if not found. Optional.
* @param string $type Filter for the variable, for valid values see {@link InputFilter::clean()}. Optional.
*
* @return mixed The request user state.
*
* @since 4.4.0
*/
public function getUserStateFromRequest($key, $request, $default = null, $type = 'none')
{
$cur_state = $this->getUserState($key, $default);
$new_state = $this->input->get($request, null, $type);
if ($new_state === null) {
return $cur_state;
}
// Save the new value only if it was set in this request.
$this->setUserState($key, $new_state);
return $new_state;
}
}