Current File : /home/pacjaorg/public_html/kmm/libraries/src/Event/AbstractEvent.php |
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Event;
use Joomla\Event\Event;
use Joomla\Event\Event as BaseEvent;
use Joomla\String\Normalise;
// phpcs:disable PSR1.Files.SideEffects
\defined('JPATH_PLATFORM') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* This class implements the base Event object used system-wide to offer orthogonality. Core objects such as Models,
* Controllers, etc create such events on-the-fly and dispatch them through the application's Dispatcher (colloquially
* known as the "Joomla! plugin system"). This way a suitable plugin, typically a "system" plugin, can modify the
* behaviour of any internal class, providing system-wide services such as tags, content versioning, comments or even
* low-level services such as the implementation of created/modified/locked behaviours, record hit counter etc.
*
* You can create a new Event with something like this:
*
* $event = AbstractEvent::create('onModelBeforeSomething', $myModel, $arguments);
*
* You can access the subject object from your event Listener using $event['subject']. It is up to your listener to
* determine whether it should apply its functionality against the subject.
*
* This AbstractEvent class implements a mutable event which is allowed to change its arguments at runtime. This is
* generally unadvisable. It's best to use AbstractImmutableEvent instead and constrict all your interaction to the
* subject class.
*
* @since 4.0.0
*/
abstract class AbstractEvent extends BaseEvent
{
use CoreEventAware;
/**
* Creates a new CMS event object for a given event name and subject. The following arguments must be given:
* subject object The subject of the event. This is the core object you are going to manipulate.
* eventClass string The Event class name. If you do not provide it Joomla\CMS\Events\<eventNameWithoutOnPrefix>
* will be used.
*
* @param string $eventName The name of the event, e.g. onTableBeforeLoad
* @param array $arguments Additional arguments to pass to the event
*
* @return static
*
* @since 4.0.0
* @throws \BadMethodCallException If you do not provide a subject argument
*/
public static function create(string $eventName, array $arguments = [])
{
// Get the class name from the arguments, if specified
$eventClassName = '';
if (isset($arguments['eventClass'])) {
$eventClassName = $arguments['eventClass'];
unset($arguments['eventClass']);
}
/**
* If the class name isn't set/found determine it from the event name, e.g. TableBeforeLoadEvent from
* the onTableBeforeLoad event name.
*/
if (empty($eventClassName) || !class_exists($eventClassName, true)) {
$bareName = strpos($eventName, 'on') === 0 ? substr($eventName, 2) : $eventName;
$parts = Normalise::fromCamelCase($bareName, true);
$eventClassName = __NAMESPACE__ . '\\' . ucfirst(array_shift($parts)) . '\\';
$eventClassName .= implode('', $parts);
$eventClassName .= 'Event';
}
// Make sure a non-empty subject argument exists and that it is an object
if (!isset($arguments['subject']) || empty($arguments['subject']) || !\is_object($arguments['subject'])) {
throw new \BadMethodCallException("No subject given for the $eventName event");
}
// Create and return the event object
if (class_exists($eventClassName, true)) {
return new $eventClassName($eventName, $arguments);
}
/**
* The detection code above failed. This is to be expected, it was written back when we only
* had the Table events. It does not address most other core events. So, let's use our
* fancier detection instead.
*/
$eventClassName = self::getEventClassByEventName($eventName);
if (!empty($eventClassName) && ($eventClassName !== Event::class)) {
return new $eventClassName($eventName, $arguments);
}
return new GenericEvent($eventName, $arguments);
}
/**
* Constructor. Overridden to go through the argument setters.
*
* @param string $name The event name.
* @param array $arguments The event arguments.
*
* @since 4.0.0
*/
public function __construct(string $name, array $arguments = [])
{
parent::__construct($name, $arguments);
$this->arguments = [];
foreach ($arguments as $argumentName => $value) {
$this->setArgument($argumentName, $value);
}
}
/**
* Get an event argument value.
* It will use a pre-processing method if one exists. The method has the signature:
*
* onGet<ArgumentName>($value): mixed
*
* where:
*
* $value is the value currently stored in the $arguments array of the event
* It returns the value to return to the caller.
*
* @param string $name The argument name.
* @param mixed $default The default value if not found.
*
* @return mixed The argument value or the default value.
*
* @since 4.0.0
*/
public function getArgument($name, $default = null)
{
// B/C check for numeric access to named argument, eg $event->getArgument('0').
if (is_numeric($name)) {
if (key($this->arguments) != 0) {
$argNames = \array_keys($this->arguments);
$name = $argNames[$name] ?? '';
}
@trigger_error(
sprintf(
'Numeric access to named event arguments is deprecated, and will not work in Joomla 6. Event %s argument %s',
\get_class($this),
$name
),
E_USER_DEPRECATED
);
}
// Look for the method for the value pre-processing/validation
$ucfirst = ucfirst($name);
$methodName1 = 'onGet' . $ucfirst;
$methodName2 = 'get' . $ucfirst;
$value = parent::getArgument($name, $default);
if (method_exists($this, $methodName1)) {
return $this->{$methodName1}($value);
} elseif (method_exists($this, $methodName2)) {
@trigger_error(
sprintf(
'Use method "%s" for value pre-processing is deprecated, and will not work in Joomla 6. Use "%s" instead. Event %s',
$methodName2,
$methodName1,
\get_class($this)
),
E_USER_DEPRECATED
);
return $this->{$methodName2}($value);
}
return $value;
}
/**
* Add argument to event.
* It will use a pre-processing method if one exists. The method has the signature:
*
* onSet<ArgumentName>($value): mixed
*
* where:
*
* $value is the value being set by the user
* It returns the value to return to set in the $arguments array of the event.
*
* @param string $name Argument name.
* @param mixed $value Value.
*
* @return $this
*
* @since 4.0.0
*/
public function setArgument($name, $value)
{
// B/C check for numeric access to named argument, eg $event->setArgument('0', $value).
if (is_numeric($name)) {
if (key($this->arguments) != 0) {
$argNames = \array_keys($this->arguments);
$name = $argNames[$name] ?? '';
}
@trigger_error(
sprintf(
'Numeric access to named event arguments is deprecated, and will not work in Joomla 6. Event %s argument %s',
\get_class($this),
$name
),
E_USER_DEPRECATED
);
}
// Look for the method for the value pre-processing/validation
$ucfirst = ucfirst($name);
$methodName1 = 'onSet' . $ucfirst;
$methodName2 = 'set' . $ucfirst;
if (method_exists($this, $methodName1)) {
$value = $this->{$methodName1}($value);
} elseif (method_exists($this, $methodName2)) {
@trigger_error(
sprintf(
'Use method "%s" for value pre-processing is deprecated, and will not work in Joomla 6. Use "%s" instead. Event %s',
$methodName2,
$methodName1,
\get_class($this)
),
E_USER_DEPRECATED
);
$value = $this->{$methodName2}($value);
}
return parent::setArgument($name, $value);
}
}