TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Extbase\Mvc\Web;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
|
||||
use TYPO3\CMS\Backend\Module\ExtbaseModule;
|
||||
use TYPO3\CMS\Core\Error\Http\PageNotFoundException;
|
||||
use TYPO3\CMS\Core\Http\UploadedFile;
|
||||
use TYPO3\CMS\Core\Routing\PageArguments;
|
||||
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
|
||||
use TYPO3\CMS\Extbase\Mvc\Exception as MvcException;
|
||||
use TYPO3\CMS\Extbase\Mvc\Exception\InvalidActionNameException;
|
||||
use TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException;
|
||||
use TYPO3\CMS\Extbase\Mvc\Exception\InvalidControllerNameException;
|
||||
use TYPO3\CMS\Extbase\Mvc\ExtbaseRequestParameters;
|
||||
use TYPO3\CMS\Extbase\Mvc\Request;
|
||||
use TYPO3\CMS\Extbase\Mvc\RequestInterface;
|
||||
use TYPO3\CMS\Extbase\Service\ExtensionService;
|
||||
|
||||
/**
|
||||
* Builds an extbase web request.
|
||||
*
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
#[Autoconfigure(public: true)]
|
||||
readonly class RequestBuilder
|
||||
{
|
||||
public function __construct(
|
||||
protected ConfigurationManagerInterface $configurationManager,
|
||||
protected ExtensionService $extensionService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Decorate a PSR-7 request as extbase web Request with the extbase attribute.
|
||||
*/
|
||||
public function build(ServerRequestInterface $mainRequest): RequestInterface
|
||||
{
|
||||
$configuration = [];
|
||||
// Parameters, which are not part of the request URL (e.g. due to "useArgumentsWithoutNamespace"), which however
|
||||
// need to be taken into account on building the extbase request. Usually those are "controller" and "action".
|
||||
$fallbackParameters = [];
|
||||
// To be used in TYPO3 Backend for Extbase modules that do not need the "namespaces" GET and POST parameters anymore.
|
||||
$useArgumentsWithoutNamespace = false;
|
||||
// Fetch requested module from the main request. This is only used for TYPO3 Backend Modules.
|
||||
$module = $mainRequest->getAttribute('module');
|
||||
if ($module instanceof ExtbaseModule) {
|
||||
$configuration = [
|
||||
'controllerConfiguration' => $module->getControllerActions(),
|
||||
];
|
||||
$useArgumentsWithoutNamespace = true;
|
||||
// Ensure the "controller" and "action" information are added as fallback parameters.
|
||||
if ($routeOptions = $mainRequest->getAttribute('route')?->getOptions()) {
|
||||
$fallbackParameters['controller'] = $routeOptions['controller'] ?? null;
|
||||
$fallbackParameters['action'] = $routeOptions['action'];
|
||||
}
|
||||
}
|
||||
$defaultValues = $this->loadDefaultValues($configuration);
|
||||
$pluginNamespace = $this->extensionService->getPluginNamespace(
|
||||
$defaultValues->getExtensionName(),
|
||||
$defaultValues->getPluginName()
|
||||
);
|
||||
$queryArguments = $mainRequest->getAttribute('routing');
|
||||
if ($useArgumentsWithoutNamespace) {
|
||||
$parameters = $mainRequest->getQueryParams();
|
||||
} elseif ($queryArguments instanceof PageArguments) {
|
||||
$parameters = $queryArguments->get($pluginNamespace) ?? [];
|
||||
} else {
|
||||
$parameters = $mainRequest->getQueryParams()[$pluginNamespace] ?? [];
|
||||
}
|
||||
$parameters = is_array($parameters) ? $parameters : [];
|
||||
if ($fallbackParameters !== []) {
|
||||
// Enhance with fallback parameters, such as "controller" and "action"
|
||||
$parameters = array_replace_recursive($fallbackParameters, $parameters);
|
||||
}
|
||||
if ($mainRequest->getMethod() === 'POST') {
|
||||
if ($useArgumentsWithoutNamespace) {
|
||||
$postParameters = $mainRequest->getParsedBody();
|
||||
} else {
|
||||
$postParameters = $mainRequest->getParsedBody()[$pluginNamespace] ?? [];
|
||||
}
|
||||
$postParameters = is_array($postParameters) ? $postParameters : [];
|
||||
$parameters = array_replace_recursive($parameters, $postParameters);
|
||||
}
|
||||
|
||||
$files = $mainRequest->getUploadedFiles();
|
||||
if (!$useArgumentsWithoutNamespace) {
|
||||
$files = $files[$pluginNamespace] ?? [];
|
||||
if ($files instanceof UploadedFile) {
|
||||
throw new InvalidArgumentNameException(
|
||||
'Using only the plugin namespace as argument name is not allowed for uploaded files. Please use plugin_namespace[argument_name] instead.',
|
||||
1722542546
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Merge UploadedFiles into request parameters, so that they are available as arguments
|
||||
// for property mapping (e.g. in ext:form or a custom file upload TypeConverter).
|
||||
$parameters = array_replace_recursive($parameters, $files);
|
||||
|
||||
$controllerClassName = $this->resolveControllerClassName($defaultValues, $parameters);
|
||||
$actionName = $this->resolveActionName($defaultValues, $controllerClassName, $parameters);
|
||||
|
||||
$extbaseAttribute = new ExtbaseRequestParameters();
|
||||
$extbaseAttribute->setPluginName($defaultValues->getPluginName());
|
||||
$extbaseAttribute->setControllerExtensionName($defaultValues->getExtensionName());
|
||||
$extbaseAttribute->setControllerAliasToClassNameMapping($defaultValues->getControllerAliasToClassMapping());
|
||||
$extbaseAttribute->setControllerName($defaultValues->getControllerAliasForControllerClassName($controllerClassName));
|
||||
$extbaseAttribute->setControllerActionName($actionName);
|
||||
$extbaseAttribute->setUploadedFiles($files);
|
||||
|
||||
if (isset($parameters['format']) && is_string($parameters['format']) && $parameters['format'] !== '') {
|
||||
$extbaseAttribute->setFormat(preg_replace('/[^a-zA-Z0-9]+/', '', $parameters['format']));
|
||||
} else {
|
||||
$extbaseAttribute->setFormat($defaultValues->getDefaultFormat());
|
||||
}
|
||||
foreach ($parameters as $argumentName => $argumentValue) {
|
||||
$extbaseAttribute->setArgument($argumentName, $argumentValue);
|
||||
}
|
||||
return new Request($mainRequest->withAttribute('extbase', $extbaseAttribute));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MvcException
|
||||
*/
|
||||
protected function loadDefaultValues(array $configuration = []): RequestBuilderDefaultValues
|
||||
{
|
||||
// todo: See comment in \TYPO3\CMS\Extbase\Core\Bootstrap::initializeConfiguration for further explanation
|
||||
// todo: on why we shouldn't use the configuration manager here.
|
||||
$configuration = array_replace_recursive($this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK), $configuration);
|
||||
try {
|
||||
return RequestBuilderDefaultValues::fromConfiguration($configuration);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw MvcException::fromPrevious($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current ControllerName extracted from given $parameters.
|
||||
* If no controller is specified, the defaultControllerName will be returned.
|
||||
* If that's not available, an exception is thrown.
|
||||
*
|
||||
* @throws InvalidControllerNameException
|
||||
* @throws MvcException if the controller could not be resolved
|
||||
* @throws PageNotFoundException
|
||||
* @return class-string
|
||||
*/
|
||||
protected function resolveControllerClassName(RequestBuilderDefaultValues $defaultValues, array $parameters): string
|
||||
{
|
||||
if (!isset($parameters['controller']) || $parameters['controller'] === '') {
|
||||
return $defaultValues->getDefaultControllerClassName();
|
||||
}
|
||||
$controllerClassName = $defaultValues->getControllerClassNameForAlias($parameters['controller']) ?? '';
|
||||
if ($defaultValues->getAllowedControllerActionsOfController($controllerClassName) === []) {
|
||||
$configuration = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
|
||||
if (isset($configuration['mvc']['throwPageNotFoundExceptionIfActionCantBeResolved']) && (bool)$configuration['mvc']['throwPageNotFoundExceptionIfActionCantBeResolved']) {
|
||||
throw new PageNotFoundException('The requested resource was not found', 1313857897);
|
||||
}
|
||||
if (isset($configuration['mvc']['callDefaultActionIfActionCantBeResolved']) && (bool)$configuration['mvc']['callDefaultActionIfActionCantBeResolved']) {
|
||||
return $defaultValues->getDefaultControllerClassName();
|
||||
}
|
||||
throw new InvalidControllerNameException(
|
||||
'The controller "' . $parameters['controller'] . '" is not allowed by plugin "' . $defaultValues->getPluginName() . '". Please check for TYPO3\\CMS\\Extbase\\Utility\\ExtensionUtility::configurePlugin() in your ext_localconf.php.',
|
||||
1313855173
|
||||
);
|
||||
}
|
||||
return preg_replace('/[^a-zA-Z0-9\\\\]+/', '', $controllerClassName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current actionName extracted from given $parameters.
|
||||
* If no action is specified, the defaultActionName will be returned.
|
||||
* If that's not available or the specified action is not defined in the current plugin, an exception is thrown.
|
||||
*
|
||||
* @param class-string $controllerClassName
|
||||
* @throws InvalidActionNameException
|
||||
* @throws MvcException
|
||||
* @throws PageNotFoundException
|
||||
* @return non-empty-string
|
||||
*/
|
||||
protected function resolveActionName(RequestBuilderDefaultValues $defaultValues, string $controllerClassName, array $parameters): string
|
||||
{
|
||||
$defaultActionName = $defaultValues->getDefaultActionName($controllerClassName);
|
||||
if (!isset($parameters['action']) || $parameters['action'] === '') {
|
||||
if ($defaultActionName === '') {
|
||||
throw new MvcException('The default action can not be determined for controller "' . $controllerClassName . '". Please check TYPO3\\CMS\\Extbase\\Utility\\ExtensionUtility::configurePlugin() in your ext_localconf.php.', 1295479651);
|
||||
}
|
||||
return $defaultActionName;
|
||||
}
|
||||
$actionName = $parameters['action'];
|
||||
$allowedActionNames = $defaultValues->getAllowedControllerActionsOfController($controllerClassName);
|
||||
if (!in_array($actionName, $allowedActionNames)) {
|
||||
$configuration = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
|
||||
if (isset($configuration['mvc']['throwPageNotFoundExceptionIfActionCantBeResolved']) && (bool)$configuration['mvc']['throwPageNotFoundExceptionIfActionCantBeResolved']) {
|
||||
throw new PageNotFoundException('The requested resource was not found', 1313857898);
|
||||
}
|
||||
if (isset($configuration['mvc']['callDefaultActionIfActionCantBeResolved']) && (bool)$configuration['mvc']['callDefaultActionIfActionCantBeResolved']) {
|
||||
if ($defaultActionName === '') {
|
||||
throw new MvcException('The default action can not be determined for controller "' . $controllerClassName . '". Please check TYPO3\\CMS\\Extbase\\Utility\\ExtensionUtility::configurePlugin() in your ext_localconf.php.', 1679048627);
|
||||
}
|
||||
return $defaultActionName;
|
||||
}
|
||||
throw new InvalidActionNameException('The action "' . $actionName . '" (controller "' . $controllerClassName . '") is not allowed by this plugin / module. Please check TYPO3\\CMS\\Extbase\\Utility\\ExtensionUtility::configurePlugin() in your ext_localconf.php / array key "controllerActions" defined in your Configuration/Backend/Modules.php.', 1313855175);
|
||||
}
|
||||
return preg_replace('/[^a-zA-Z0-9]+/', '', $actionName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Extbase\Mvc\Web;
|
||||
|
||||
/**
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
final class RequestBuilderDefaultValues
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $extensionName
|
||||
* @param non-empty-string $pluginName
|
||||
* @param class-string $defaultControllerClassName
|
||||
* @param non-empty-string $defaultControllerAlias
|
||||
* @param non-empty-string $defaultFormat
|
||||
*/
|
||||
private function __construct(
|
||||
private readonly string $extensionName,
|
||||
private readonly string $pluginName,
|
||||
private readonly string $defaultControllerClassName,
|
||||
private readonly string $defaultControllerAlias,
|
||||
private readonly string $defaultFormat,
|
||||
private readonly array $allowedControllerActions,
|
||||
private readonly array $controllerAliasToClassMapping,
|
||||
private readonly array $controllerClassToAliasMapping,
|
||||
) {}
|
||||
|
||||
public static function fromConfiguration(array $configuration): self
|
||||
{
|
||||
$extensionName = $configuration['extensionName'] ?? null;
|
||||
$extensionName = is_string($extensionName) && $extensionName !== '' ? $extensionName : null;
|
||||
|
||||
$pluginName = $configuration['pluginName'] ?? null;
|
||||
$pluginName = is_string($pluginName) && $pluginName !== '' ? $pluginName : null;
|
||||
|
||||
$controllerConfigurations = $configuration['controllerConfiguration'] ?? [];
|
||||
$controllerConfigurations = is_array($controllerConfigurations) ? $controllerConfigurations : [];
|
||||
|
||||
if (!is_string($extensionName)) {
|
||||
throw new \InvalidArgumentException('"extensionName" is not properly configured. Request can\'t be dispatched!', 1289843275);
|
||||
}
|
||||
if (!is_string($pluginName)) {
|
||||
throw new \InvalidArgumentException('"pluginName" is not properly configured. Request can\'t be dispatched!', 1289843277);
|
||||
}
|
||||
|
||||
if ($controllerConfigurations === []) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf(
|
||||
'The default controller for extension "%s" and plugin "%s" can not be determined. '
|
||||
. 'Please check for TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin() in your ext_localconf.php.',
|
||||
$extensionName,
|
||||
$pluginName
|
||||
),
|
||||
1316104317
|
||||
);
|
||||
}
|
||||
|
||||
$defaultFormat = $configuration['format'] ?? null;
|
||||
$defaultFormat = is_string($defaultFormat) && $defaultFormat !== '' ? $defaultFormat : 'html';
|
||||
|
||||
$defaultControllerClassName = null;
|
||||
$defaultControllerAlias = null;
|
||||
|
||||
$allowedControllerActions = [];
|
||||
$controllerClassToAliasMapping = [];
|
||||
$controllerAliasToClassMapping = [];
|
||||
|
||||
$firstItem = true;
|
||||
foreach ($controllerConfigurations as $controllerClassName => $controllerConfiguration) {
|
||||
if (!is_string($controllerClassName) || $controllerClassName === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_array($controllerConfiguration)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$actions = $controllerConfiguration['actions'] ?? [];
|
||||
$actions = is_array($actions) ? $actions : [];
|
||||
|
||||
if ($actions === []) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$controllerClassName = $controllerConfiguration['className'] ?? null;
|
||||
$controllerClassName = is_string($controllerClassName) && $controllerClassName !== '' ? $controllerClassName : null;
|
||||
|
||||
if ($controllerClassName === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$controllerAlias = $controllerConfiguration['alias'] ?? null;
|
||||
$controllerAlias = is_string($controllerAlias) && $controllerAlias !== '' ? $controllerAlias : null;
|
||||
|
||||
if ($controllerAlias === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$allowedControllerActions[$controllerClassName] = $actions;
|
||||
$controllerClassToAliasMapping[$controllerClassName] = $controllerAlias;
|
||||
$controllerAliasToClassMapping[$controllerAlias] = $controllerClassName;
|
||||
|
||||
if ($firstItem) {
|
||||
$defaultControllerClassName = $controllerClassName;
|
||||
$defaultControllerAlias = $controllerAlias;
|
||||
}
|
||||
|
||||
$firstItem = false;
|
||||
}
|
||||
|
||||
if ($defaultControllerClassName === null || $defaultControllerAlias === null) {
|
||||
throw new \LogicException(
|
||||
'Either $defaultControllerClassName or $defaultControllerAlias are unexpectedly null',
|
||||
1679051921
|
||||
);
|
||||
}
|
||||
|
||||
if ($allowedControllerActions === []) {
|
||||
throw new \LengthException(
|
||||
'$allowedControllerActions is expected to not be empty',
|
||||
1679051891
|
||||
);
|
||||
}
|
||||
|
||||
return new self(
|
||||
$extensionName,
|
||||
$pluginName,
|
||||
$defaultControllerClassName,
|
||||
$defaultControllerAlias,
|
||||
$defaultFormat,
|
||||
$allowedControllerActions,
|
||||
$controllerAliasToClassMapping,
|
||||
$controllerClassToAliasMapping,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getExtensionName(): string
|
||||
{
|
||||
return $this->extensionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getPluginName(): string
|
||||
{
|
||||
return $this->pluginName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string
|
||||
*/
|
||||
public function getDefaultControllerClassName(): string
|
||||
{
|
||||
return $this->defaultControllerClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getDefaultControllerAlias(): string
|
||||
{
|
||||
return $this->defaultControllerAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getDefaultFormat(): string
|
||||
{
|
||||
return $this->defaultFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<class-string, list<string>>
|
||||
*/
|
||||
public function getAllowedControllerActions(): array
|
||||
{
|
||||
return $this->allowedControllerActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getAllowedControllerActionsOfController(string $controllerClassName): array
|
||||
{
|
||||
return $this->allowedControllerActions[$controllerClassName] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, class-string>
|
||||
*/
|
||||
public function getControllerAliasToClassMapping(): array
|
||||
{
|
||||
return $this->controllerAliasToClassMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<class-string, non-empty-string>
|
||||
*/
|
||||
public function getControllerClassToAliasMapping(): array
|
||||
{
|
||||
return $this->controllerClassToAliasMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $controllerAlias
|
||||
* @return class-string|null
|
||||
*/
|
||||
public function getControllerClassNameForAlias(string $controllerAlias): ?string
|
||||
{
|
||||
return $this->controllerAliasToClassMapping[$controllerAlias] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $controllerClassName
|
||||
* @return non-empty-string|null
|
||||
*/
|
||||
public function getControllerAliasForControllerClassName(string $controllerClassName): ?string
|
||||
{
|
||||
return $this->controllerClassToAliasMapping[$controllerClassName] ?? null;
|
||||
}
|
||||
|
||||
public function getDefaultActionName(string $controllerClassName): ?string
|
||||
{
|
||||
$actions = $this->allowedControllerActions[$controllerClassName] ?? [];
|
||||
return $actions[0] ?? null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,647 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Extbase\Mvc\Web\Routing;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
|
||||
use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException;
|
||||
use TYPO3\CMS\Backend\Routing\Route;
|
||||
use TYPO3\CMS\Core\Http\ApplicationType;
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\DomainObject\AbstractValueObject;
|
||||
use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface;
|
||||
use TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentValueException;
|
||||
use TYPO3\CMS\Extbase\Mvc\RequestInterface;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy;
|
||||
use TYPO3\CMS\Extbase\Service\ExtensionService;
|
||||
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
|
||||
|
||||
/**
|
||||
* URI Builder for extbase requests.
|
||||
*/
|
||||
#[Autoconfigure(public: true, shared: false)]
|
||||
class UriBuilder
|
||||
{
|
||||
protected RequestInterface $request;
|
||||
|
||||
protected array $arguments = [];
|
||||
protected array $lastArguments = [];
|
||||
protected string $section = '';
|
||||
protected bool $createAbsoluteUri = false;
|
||||
protected ?string $absoluteUriScheme = null;
|
||||
protected bool|string|int $addQueryString = false;
|
||||
protected array $argumentsToBeExcludedFromQueryString = [];
|
||||
protected bool $linkAccessRestrictedPages = false;
|
||||
protected ?int $targetPageUid = null;
|
||||
protected int $targetPageType = 0;
|
||||
protected ?string $language = null;
|
||||
protected bool $noCache = false;
|
||||
protected string $format = '';
|
||||
protected ?string $argumentPrefix = null;
|
||||
|
||||
public function __construct(
|
||||
protected readonly ExtensionService $extensionService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Sets the current request
|
||||
*
|
||||
* @return static the current UriBuilder to allow method chaining
|
||||
*/
|
||||
public function setRequest(RequestInterface $request): UriBuilder
|
||||
{
|
||||
$this->request = $request;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional query parameters.
|
||||
* If you want to "prefix" arguments, you can pass in multidimensional arrays:
|
||||
* array('prefix1' => array('foo' => 'bar')) gets "&prefix1[foo]=bar"
|
||||
*
|
||||
* @return static the current UriBuilder to allow method chaining
|
||||
*/
|
||||
public function setArguments(array $arguments): UriBuilder
|
||||
{
|
||||
$this->arguments = $arguments;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function getArguments(): array
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* If specified, adds a given HTML anchor to the URI (#...)
|
||||
*
|
||||
* @return static the current UriBuilder to allow method chaining
|
||||
*/
|
||||
public function setSection(string $section): UriBuilder
|
||||
{
|
||||
$this->section = $section;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function getSection(): string
|
||||
{
|
||||
return $this->section;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the format of the target (e.g. "html" or "xml")
|
||||
*
|
||||
* @return static the current UriBuilder to allow method chaining
|
||||
*/
|
||||
public function setFormat(string $format): UriBuilder
|
||||
{
|
||||
$this->format = $format;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function getFormat(): string
|
||||
{
|
||||
return $this->format;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set, the URI is prepended with the current base URI. Defaults to FALSE.
|
||||
*
|
||||
* @return static the current UriBuilder to allow method chaining
|
||||
*/
|
||||
public function setCreateAbsoluteUri(bool $createAbsoluteUri): UriBuilder
|
||||
{
|
||||
$this->createAbsoluteUri = $createAbsoluteUri;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function getCreateAbsoluteUri(): bool
|
||||
{
|
||||
return $this->createAbsoluteUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function getAbsoluteUriScheme(): ?string
|
||||
{
|
||||
return $this->absoluteUriScheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the scheme that should be used for absolute URIs in FE mode
|
||||
*
|
||||
* @param string $absoluteUriScheme the scheme to be used for absolute URIs
|
||||
* @return static the current UriBuilder to allow method chaining
|
||||
*/
|
||||
public function setAbsoluteUriScheme(string $absoluteUriScheme): UriBuilder
|
||||
{
|
||||
$this->absoluteUriScheme = $absoluteUriScheme;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces a URI / link to a page to a specific language (or use "current")
|
||||
*/
|
||||
public function setLanguage(?string $language): UriBuilder
|
||||
{
|
||||
$this->language = $language;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function getLanguage(): ?string
|
||||
{
|
||||
return $this->language;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set, the current query parameters will be merged with $this->arguments in backend context.
|
||||
* In frontend context, setting this property will only include mapped query arguments from the
|
||||
* Page Routing. To include any - possible "unsafe" - GET parameters, the property has to be set
|
||||
* to "untrusted". Defaults to FALSE.
|
||||
*
|
||||
* @param bool|string|int $addQueryString is set to "1", "true", "0", "false" or "untrusted"
|
||||
* @return static the current UriBuilder to allow method chaining
|
||||
* @see https://docs.typo3.org/m/typo3/reference-typoscript/main/en-us/Functions/Typolink.html#addquerystring
|
||||
*/
|
||||
public function setAddQueryString(bool|string|int $addQueryString): UriBuilder
|
||||
{
|
||||
$this->addQueryString = $addQueryString;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function getAddQueryString(): bool|string|int
|
||||
{
|
||||
return $this->addQueryString;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of arguments to be excluded from the query parameters
|
||||
* Only active if addQueryString is set
|
||||
*
|
||||
* @return static the current UriBuilder to allow method chaining
|
||||
* @see https://docs.typo3.org/m/typo3/reference-typoscript/main/en-us/Functions/Typolink.html#addquerystring
|
||||
* @see setAddQueryString()
|
||||
*/
|
||||
public function setArgumentsToBeExcludedFromQueryString(array $argumentsToBeExcludedFromQueryString): UriBuilder
|
||||
{
|
||||
$this->argumentsToBeExcludedFromQueryString = $argumentsToBeExcludedFromQueryString;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function getArgumentsToBeExcludedFromQueryString(): array
|
||||
{
|
||||
return $this->argumentsToBeExcludedFromQueryString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the prefix to be used for all arguments.
|
||||
*
|
||||
* @return static the current UriBuilder to allow method chaining
|
||||
*/
|
||||
public function setArgumentPrefix(string $argumentPrefix): UriBuilder
|
||||
{
|
||||
$this->argumentPrefix = $argumentPrefix;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function getArgumentPrefix(): ?string
|
||||
{
|
||||
return $this->argumentPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set, URIs for pages without access permissions will be created
|
||||
*
|
||||
* @return static the current UriBuilder to allow method chaining
|
||||
*/
|
||||
public function setLinkAccessRestrictedPages(bool $linkAccessRestrictedPages): UriBuilder
|
||||
{
|
||||
$this->linkAccessRestrictedPages = $linkAccessRestrictedPages;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function getLinkAccessRestrictedPages(): bool
|
||||
{
|
||||
return $this->linkAccessRestrictedPages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uid of the target page
|
||||
*
|
||||
* @return static the current UriBuilder to allow method chaining
|
||||
*/
|
||||
public function setTargetPageUid(int $targetPageUid): UriBuilder
|
||||
{
|
||||
$this->targetPageUid = $targetPageUid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function getTargetPageUid(): ?int
|
||||
{
|
||||
return $this->targetPageUid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the page type of the target URI. Defaults to 0
|
||||
*
|
||||
* @return static the current UriBuilder to allow method chaining
|
||||
*/
|
||||
public function setTargetPageType(int $targetPageType): UriBuilder
|
||||
{
|
||||
$this->targetPageType = $targetPageType;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function getTargetPageType(): int
|
||||
{
|
||||
return $this->targetPageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* by default FALSE; if TRUE, &no_cache=1 will be appended to the URI
|
||||
*
|
||||
* @return static the current UriBuilder to allow method chaining
|
||||
*/
|
||||
public function setNoCache(bool $noCache): UriBuilder
|
||||
{
|
||||
$this->noCache = $noCache;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function getNoCache(): bool
|
||||
{
|
||||
return $this->noCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the arguments being used for the last URI being built.
|
||||
* This is only set after build() / uriFor() has been called.
|
||||
*
|
||||
* @return array The last arguments
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function getLastArguments(): array
|
||||
{
|
||||
return $this->lastArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all UriBuilder options to their default value
|
||||
*
|
||||
* @return static the current UriBuilder to allow method chaining
|
||||
*/
|
||||
public function reset(): UriBuilder
|
||||
{
|
||||
$this->arguments = [];
|
||||
$this->section = '';
|
||||
$this->format = '';
|
||||
$this->language = null;
|
||||
$this->createAbsoluteUri = false;
|
||||
$this->addQueryString = false;
|
||||
$this->argumentsToBeExcludedFromQueryString = [];
|
||||
$this->linkAccessRestrictedPages = false;
|
||||
$this->targetPageUid = null;
|
||||
$this->targetPageType = 0;
|
||||
$this->noCache = false;
|
||||
$this->argumentPrefix = null;
|
||||
$this->absoluteUriScheme = null;
|
||||
// $this->request MUST NOT be reset here because the request is actually a hard dependency
|
||||
// and not part of the internal state of this object.
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a URI used for linking to an Extbase action.
|
||||
* Works in Frontend and Backend mode of TYPO3.
|
||||
*
|
||||
* @param string|null $actionName Name of the action to be called
|
||||
* @param array|null $controllerArguments Additional query parameters. Will be "namespaced" and merged with $this->arguments.
|
||||
* @param string|null $controllerName Name of the target controller. If not set, current ControllerName is used.
|
||||
* @param string|null $extensionName Name of the target extension, without underscores. If not set, current ExtensionName is used.
|
||||
* @param string|null $pluginName Name of the target plugin. If not set, current PluginName is used.
|
||||
* @return string the rendered URI
|
||||
* @see build()
|
||||
*/
|
||||
public function uriFor(
|
||||
?string $actionName = null,
|
||||
?array $controllerArguments = null,
|
||||
?string $controllerName = null,
|
||||
?string $extensionName = null,
|
||||
?string $pluginName = null
|
||||
): string {
|
||||
$controllerArguments = $controllerArguments ?? [];
|
||||
|
||||
if ($actionName !== null) {
|
||||
$controllerArguments['action'] = $actionName;
|
||||
}
|
||||
if ($controllerName !== null) {
|
||||
$controllerArguments['controller'] = $controllerName;
|
||||
} else {
|
||||
$controllerArguments['controller'] = $this->request->getControllerName();
|
||||
}
|
||||
if ($extensionName === null) {
|
||||
$extensionName = $this->request->getControllerExtensionName();
|
||||
}
|
||||
$isFrontend = ApplicationType::fromRequest($this->request)->isFrontend();
|
||||
if ($pluginName === null && $isFrontend) {
|
||||
$pluginName = $this->extensionService->getPluginNameByAction($extensionName, $controllerArguments['controller'], $controllerArguments['action'] ?? null);
|
||||
}
|
||||
if ($pluginName === null) {
|
||||
$pluginName = $this->request->getPluginName();
|
||||
}
|
||||
if ($this->targetPageUid === null && $isFrontend) {
|
||||
$this->targetPageUid = $this->extensionService->getTargetPidByPlugin($extensionName, $pluginName);
|
||||
}
|
||||
if ($this->format !== '') {
|
||||
$controllerArguments['format'] = $this->format;
|
||||
}
|
||||
if ($this->argumentPrefix !== null) {
|
||||
$prefixedControllerArguments = [$this->argumentPrefix => $controllerArguments];
|
||||
} elseif (!$isFrontend) {
|
||||
$prefixedControllerArguments = $controllerArguments;
|
||||
// Backend UriBuilder needs the route, which usually maps to the "route" parameter, which can be
|
||||
// found in "Configuration/Backend/Modules.php" as the main key - that is the actual base route
|
||||
// for the backend module, which in Extbase-speak is called a "pluginName"
|
||||
$prefixedControllerArguments['route'] = $pluginName;
|
||||
} else {
|
||||
$pluginNamespace = $this->extensionService->getPluginNamespace($extensionName, $pluginName);
|
||||
$prefixedControllerArguments = [$pluginNamespace => $controllerArguments];
|
||||
}
|
||||
ArrayUtility::mergeRecursiveWithOverrule($this->arguments, $prefixedControllerArguments);
|
||||
return $this->build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the URI
|
||||
* Depending on the current context this calls buildBackendUri() or buildFrontendUri()
|
||||
*
|
||||
* @return string The URI
|
||||
* @see buildBackendUri()
|
||||
* @see buildFrontendUri()
|
||||
*/
|
||||
public function build(): string
|
||||
{
|
||||
if (ApplicationType::fromRequest($this->request)->isBackend()) {
|
||||
return $this->buildBackendUri();
|
||||
}
|
||||
return $this->buildFrontendUri();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the URI, backend flavour
|
||||
* The settings pageUid, pageType, noCache & linkAccessRestrictedPages
|
||||
* will be ignored in the backend.
|
||||
*
|
||||
* @return string The URI
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function buildBackendUri(): string
|
||||
{
|
||||
$arguments = [];
|
||||
if ($this->addQueryString && $this->addQueryString !== 'false') {
|
||||
$arguments = $this->request->getQueryParams();
|
||||
foreach ($this->argumentsToBeExcludedFromQueryString as $argumentToBeExcluded) {
|
||||
$argumentArrayToBeExcluded = [];
|
||||
parse_str($argumentToBeExcluded, $argumentArrayToBeExcluded);
|
||||
$arguments = ArrayUtility::arrayDiffKeyRecursive($arguments, $argumentArrayToBeExcluded);
|
||||
}
|
||||
} else {
|
||||
$id = $this->request->getParsedBody()['id'] ?? $this->request->getQueryParams()['id'] ?? null;
|
||||
if ($id !== null) {
|
||||
$arguments['id'] = $id;
|
||||
}
|
||||
}
|
||||
if (($route = $this->request->getAttribute('route')) instanceof Route) {
|
||||
/** @var Route $route */
|
||||
$arguments['route'] = $route->getOption('_identifier');
|
||||
}
|
||||
$arguments = array_replace_recursive($arguments, $this->arguments);
|
||||
$arguments = $this->convertDomainObjectsToIdentityArrays($arguments);
|
||||
$this->lastArguments = $arguments;
|
||||
$routeIdentifier = $arguments['route'] ?? null;
|
||||
unset($arguments['route'], $arguments['token']);
|
||||
|
||||
// In case the current route identifier is an identifier of a sub route, remove the sub route
|
||||
// part to be able to add the actually requested sub route based on the current arguments.
|
||||
if ($routeIdentifier && str_contains($routeIdentifier, '.')) {
|
||||
[$routeIdentifier] = explode('.', $routeIdentifier);
|
||||
}
|
||||
// Build route identifier to the actually requested sub route (controller / action pair) - if any -
|
||||
// and unset corresponding arguments.
|
||||
if ($routeIdentifier && isset($arguments['controller'], $arguments['action'])) {
|
||||
$routeIdentifier .= '.' . $arguments['controller'] . '_' . $arguments['action'];
|
||||
unset($arguments['controller'], $arguments['action']);
|
||||
}
|
||||
$uri = '';
|
||||
if ($routeIdentifier) {
|
||||
$backendUriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
|
||||
try {
|
||||
if ($this->createAbsoluteUri) {
|
||||
$uri = (string)$backendUriBuilder->buildUriFromRoute($routeIdentifier, $arguments, \TYPO3\CMS\Backend\Routing\UriBuilder::ABSOLUTE_URL);
|
||||
} else {
|
||||
$uri = (string)$backendUriBuilder->buildUriFromRoute($routeIdentifier, $arguments);
|
||||
}
|
||||
} catch (RouteNotFoundException) {
|
||||
// empty URL
|
||||
}
|
||||
}
|
||||
if ($this->section !== '') {
|
||||
$uri .= '#' . $this->section;
|
||||
}
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the URI, frontend flavour
|
||||
*
|
||||
* @return string The URI
|
||||
* @see buildTypolinkConfiguration()
|
||||
* @internal only to be used within Extbase, not part of TYPO3 Core API.
|
||||
*/
|
||||
public function buildFrontendUri(): string
|
||||
{
|
||||
$typolinkConfiguration = $this->buildTypolinkConfiguration();
|
||||
if ($this->createAbsoluteUri === true) {
|
||||
$typolinkConfiguration['forceAbsoluteUrl'] = true;
|
||||
if ($this->absoluteUriScheme !== null) {
|
||||
$typolinkConfiguration['forceAbsoluteUrl.']['scheme'] = $this->absoluteUriScheme;
|
||||
}
|
||||
}
|
||||
/** @var ?ContentObjectRenderer $currentContentObject */
|
||||
$currentContentObject = $this->request->getAttribute('currentContentObject');
|
||||
return $currentContentObject?->createUrl($typolinkConfiguration) ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a TypoLink configuration array from the current settings
|
||||
*
|
||||
* @return array typolink configuration array
|
||||
* @see https://docs.typo3.org/m/typo3/reference-typoscript/main/en-us/Functions/Typolink.html
|
||||
*/
|
||||
protected function buildTypolinkConfiguration(): array
|
||||
{
|
||||
$typolinkConfiguration = [];
|
||||
$typolinkConfiguration['parameter'] = $this->targetPageUid ?? $this->request->getAttribute('frontend.page.information')?->getId() ?? '';
|
||||
if ($this->targetPageType !== 0) {
|
||||
$typolinkConfiguration['parameter'] .= ',' . $this->targetPageType;
|
||||
} elseif ($this->format !== '') {
|
||||
$targetPageType = $this->extensionService->getTargetPageTypeByFormat($this->request->getControllerExtensionName(), $this->format);
|
||||
$typolinkConfiguration['parameter'] .= ',' . $targetPageType;
|
||||
}
|
||||
if (!empty($this->arguments)) {
|
||||
$arguments = $this->convertDomainObjectsToIdentityArrays($this->arguments);
|
||||
$this->lastArguments = $arguments;
|
||||
$typolinkConfiguration['queryParameters'] = $arguments;
|
||||
}
|
||||
if ($this->addQueryString && $this->addQueryString !== 'false') {
|
||||
$typolinkConfiguration['addQueryString'] = $this->addQueryString;
|
||||
if (!empty($this->argumentsToBeExcludedFromQueryString)) {
|
||||
$typolinkConfiguration['addQueryString.'] = [
|
||||
'exclude' => implode(',', $this->argumentsToBeExcludedFromQueryString),
|
||||
];
|
||||
}
|
||||
}
|
||||
if ($this->language !== null) {
|
||||
$typolinkConfiguration['language'] = $this->language;
|
||||
}
|
||||
if ($this->noCache === true) {
|
||||
$typolinkConfiguration['no_cache'] = 1;
|
||||
}
|
||||
if ($this->section !== '') {
|
||||
$typolinkConfiguration['section'] = $this->section;
|
||||
}
|
||||
if ($this->linkAccessRestrictedPages === true) {
|
||||
$typolinkConfiguration['linkAccessRestrictedPages'] = 1;
|
||||
}
|
||||
return $typolinkConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively iterates through the specified arguments and turns instances of type \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
|
||||
* into an arrays containing the uid of the domain object.
|
||||
*
|
||||
* @param array $arguments The arguments to be iterated
|
||||
* @throws InvalidArgumentValueException
|
||||
* @return array The modified arguments array
|
||||
*/
|
||||
protected function convertDomainObjectsToIdentityArrays(array $arguments): array
|
||||
{
|
||||
foreach ($arguments as $argumentKey => $argumentValue) {
|
||||
// if we have a LazyLoadingProxy here, make sure to get the real instance for further processing
|
||||
if ($argumentValue instanceof LazyLoadingProxy) {
|
||||
$argumentValue = $argumentValue->_loadRealInstance();
|
||||
// also update the value in the arguments array, because the lazyLoaded object could be
|
||||
// hidden and thus the $argumentValue would be NULL.
|
||||
$arguments[$argumentKey] = $argumentValue;
|
||||
}
|
||||
if ($argumentValue instanceof \Iterator) {
|
||||
$argumentValue = $this->convertIteratorToArray($argumentValue);
|
||||
}
|
||||
if ($argumentValue instanceof DomainObjectInterface) {
|
||||
if ($argumentValue->getUid() !== null) {
|
||||
$arguments[$argumentKey] = $argumentValue->getUid();
|
||||
} elseif ($argumentValue instanceof AbstractValueObject) {
|
||||
$arguments[$argumentKey] = $this->convertTransientObjectToArray($argumentValue);
|
||||
} else {
|
||||
throw new InvalidArgumentValueException('Could not serialize Domain Object ' . get_class($argumentValue) . '. It is neither an Entity with identity properties set, nor a Value Object.', 1260881688);
|
||||
}
|
||||
} elseif (is_array($argumentValue)) {
|
||||
$arguments[$argumentKey] = $this->convertDomainObjectsToIdentityArrays($argumentValue);
|
||||
} elseif ($argumentValue instanceof \UnitEnum) {
|
||||
$arguments[$argumentKey] = $argumentValue->value ?? $argumentValue->name;
|
||||
} elseif ($argumentValue instanceof \Stringable) {
|
||||
$arguments[$argumentKey] = (string)$argumentValue;
|
||||
}
|
||||
}
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
protected function convertIteratorToArray(\Iterator $iterator): array
|
||||
{
|
||||
if (method_exists($iterator, 'toArray')) {
|
||||
$array = $iterator->toArray();
|
||||
} else {
|
||||
$array = iterator_to_array($iterator);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a given object recursively into an array.
|
||||
*
|
||||
* @todo Refactor this into convertDomainObjectsToIdentityArrays()
|
||||
*/
|
||||
protected function convertTransientObjectToArray(DomainObjectInterface $object): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($object->_getProperties() as $propertyName => $propertyValue) {
|
||||
if ($propertyValue instanceof \Iterator) {
|
||||
$propertyValue = $this->convertIteratorToArray($propertyValue);
|
||||
}
|
||||
if ($propertyValue instanceof DomainObjectInterface) {
|
||||
if ($propertyValue->getUid() !== null) {
|
||||
$result[$propertyName] = $propertyValue->getUid();
|
||||
} else {
|
||||
$result[$propertyName] = $this->convertTransientObjectToArray($propertyValue);
|
||||
}
|
||||
} elseif (is_array($propertyValue)) {
|
||||
$result[$propertyName] = $this->convertDomainObjectsToIdentityArrays($propertyValue);
|
||||
} else {
|
||||
$result[$propertyName] = $propertyValue;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user