first commit
This commit is contained in:
commit
1218dd1517
12716 files changed
+989233
No files matched your search
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Extbase\SignalSlot;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use TYPO3\CMS\Core\Log\LogManager;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Object\ObjectManager;
|
||||
|
||||
/**
|
||||
* A dispatcher which dispatches signals by calling its registered slot methods
|
||||
* and passing them the method arguments which were originally passed to the
|
||||
* signal method.
|
||||
*/
|
||||
class Dispatcher implements \TYPO3\CMS\Core\SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isInitialized = false;
|
||||
|
||||
/**
|
||||
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
|
||||
*/
|
||||
protected $objectManager;
|
||||
|
||||
/**
|
||||
* Information about all slots connected a certain signal.
|
||||
* Indexed by [$signalClassName][$signalMethodName] and then numeric with an
|
||||
* array of information about the slot
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $slots = [];
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* Initializes this object.
|
||||
*
|
||||
* This methods needs to be used as alternative to inject aspects.
|
||||
* Since this dispatches is used very early when the ObjectManager
|
||||
* is not fully initialized (especially concerning caching framework),
|
||||
* this is the only way.
|
||||
*/
|
||||
public function initializeObject()
|
||||
{
|
||||
if (!$this->isInitialized) {
|
||||
$this->objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
||||
$logManager = GeneralUtility::makeInstance(LogManager::class);
|
||||
$this->logger = $logManager->getLogger(self::class);
|
||||
$this->isInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects a signal with a slot.
|
||||
* One slot can be connected with multiple signals by calling this method multiple times.
|
||||
*
|
||||
* @param string $signalClassName Name of the class containing the signal
|
||||
* @param string $signalName Name of the signal
|
||||
* @param mixed $slotClassNameOrObject Name of the class containing the slot or the instantiated class or a Closure object
|
||||
* @param string $slotMethodName Name of the method to be used as a slot. If $slotClassNameOrObject is a Closure object, this parameter is ignored
|
||||
* @param bool $passSignalInformation If set to TRUE, the last argument passed to the slot will be information about the signal (EmitterClassName::signalName)
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function connect($signalClassName, $signalName, $slotClassNameOrObject, $slotMethodName = '', $passSignalInformation = true)
|
||||
{
|
||||
$class = null;
|
||||
$object = null;
|
||||
if (is_object($slotClassNameOrObject)) {
|
||||
$object = $slotClassNameOrObject;
|
||||
$method = $slotClassNameOrObject instanceof \Closure ? '__invoke' : $slotMethodName;
|
||||
} else {
|
||||
if ($slotMethodName === '') {
|
||||
throw new \InvalidArgumentException('The slot method name must not be empty (except for closures).', 1229531659);
|
||||
}
|
||||
$class = $slotClassNameOrObject;
|
||||
$method = $slotMethodName;
|
||||
}
|
||||
$slot = [
|
||||
'class' => $class,
|
||||
'method' => $method,
|
||||
'object' => $object,
|
||||
'passSignalInformation' => $passSignalInformation === true,
|
||||
];
|
||||
// The in_array() comparision needs to be strict to avoid potential issues
|
||||
// with complex objects being registered as slot.
|
||||
if (!is_array($this->slots[$signalClassName][$signalName] ?? false) || !in_array($slot, $this->slots[$signalClassName][$signalName], true)) {
|
||||
$this->slots[$signalClassName][$signalName][] = $slot;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a signal by calling the registered Slot methods
|
||||
*
|
||||
* @param string $signalClassName Name of the class containing the signal
|
||||
* @param string $signalName Name of the signal
|
||||
* @param array $signalArguments arguments passed to the signal method
|
||||
* @return mixed
|
||||
* @throws Exception\InvalidSlotException if the slot is not valid
|
||||
* @throws Exception\InvalidSlotReturnException if a slot returns invalid arguments (too few or return value is not an array)
|
||||
*/
|
||||
public function dispatch($signalClassName, $signalName, array $signalArguments = [])
|
||||
{
|
||||
$this->initializeObject();
|
||||
$this->logger->debug(
|
||||
'Triggered signal ' . $signalClassName . ' ' . $signalName,
|
||||
[
|
||||
'signalClassName' => $signalClassName,
|
||||
'signalName' => $signalName,
|
||||
'signalArguments' => $signalArguments,
|
||||
]
|
||||
);
|
||||
if (!isset($this->slots[$signalClassName][$signalName])) {
|
||||
return $signalArguments;
|
||||
}
|
||||
foreach ($this->slots[$signalClassName][$signalName] as $slotInformation) {
|
||||
if (isset($slotInformation['object'])) {
|
||||
$object = $slotInformation['object'];
|
||||
} else {
|
||||
if (!isset($this->objectManager)) {
|
||||
throw new Exception\InvalidSlotException(sprintf('Cannot dispatch %s::%s to class %s. The object manager is not yet available in the Signal Slot Dispatcher and therefore it cannot dispatch classes.', $signalClassName, $signalName, $slotInformation['class'] ?? ''), 1298113624);
|
||||
}
|
||||
if (!$this->objectManager->isRegistered($slotInformation['class'])) {
|
||||
throw new Exception\InvalidSlotException('The given class "' . $slotInformation['class'] . '" is not a registered object.', 1245673367);
|
||||
}
|
||||
$object = $this->objectManager->get($slotInformation['class']);
|
||||
}
|
||||
|
||||
if (!method_exists($object, $slotInformation['method'])) {
|
||||
throw new Exception\InvalidSlotException('The slot method ' . get_class($object) . '->' . $slotInformation['method'] . '() does not exist.', 1245673368);
|
||||
}
|
||||
|
||||
$preparedSlotArguments = $signalArguments;
|
||||
if ($slotInformation['passSignalInformation'] === true) {
|
||||
$preparedSlotArguments[] = $signalClassName . '::' . $signalName;
|
||||
}
|
||||
|
||||
$slotReturn = call_user_func_array([$object, $slotInformation['method']], $preparedSlotArguments);
|
||||
|
||||
if ($slotReturn) {
|
||||
if (!is_array($slotReturn)) {
|
||||
throw new Exception\InvalidSlotReturnException('The slot method ' . get_class($object) . '->' . $slotInformation['method'] . '()\'s return value is of an not allowed type ('
|
||||
. gettype($slotReturn) . ').', 1376683067);
|
||||
}
|
||||
if (count($slotReturn) !== count($signalArguments)) {
|
||||
throw new Exception\InvalidSlotReturnException('The slot method ' . get_class($object) . '->' . $slotInformation['method'] . '() returned a different number ('
|
||||
. count($slotReturn) . ') of arguments, than it received (' . count($signalArguments) . ').', 1376683066);
|
||||
}
|
||||
$signalArguments = $slotReturn;
|
||||
}
|
||||
}
|
||||
|
||||
return $signalArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all slots which are connected with the given signal
|
||||
*
|
||||
* @param string $signalClassName Name of the class containing the signal
|
||||
* @param string $signalName Name of the signal
|
||||
* @return array An array of arrays with slot information
|
||||
*/
|
||||
public function getSlots($signalClassName, $signalName)
|
||||
{
|
||||
return $this->slots[$signalClassName][$signalName] ?? [];
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user