Commit d30ba9cf authored by Christian Kuhn's avatar Christian Kuhn
Browse files

[TASK] Avoid ObjectManager in ext:extbase

This finishes removal of regular extbase ObjectManager
usages throughout the core: All left over places are
fallback situations if extensions don't provide proper
service definitions.

Most places are casual replacements, many of them have
been prepared with previous patches. Some places like
Query and QueryResult still need special handling: The
patch introduces some 'ForwardCompatible' interfaces
implemented by core to otherwise OM-fallback if extensions
didn't catch up yet. This avoids expensive runtime
reflection in potentially often-called areas.

When this patch is merged, a final patch can be done,
including a ReST with some dedicated transition tips
and the ultimate ObjectManager deprecation.

Resolves: #94451
Related: #90803
Related: #92238
Releases: master
Change-Id: Ic53f3bf6a04d15052680a953c76d19182a2e5e87
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/69676

Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Tested-by: Jochen's avatarJochen <rothjochen@gmail.com>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Reviewed-by: Jochen's avatarJochen <rothjochen@gmail.com>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
parent 129452ff
......@@ -141,7 +141,7 @@ abstract class ActionController implements ControllerInterface
protected $signalSlotDispatcher;
/**
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
* @var ObjectManagerInterface
* @internal only to be used within Extbase, not part of TYPO3 Core API.
*/
protected $objectManager;
......@@ -170,7 +170,7 @@ abstract class ActionController implements ControllerInterface
protected $arguments;
/**
* @var \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext
* @var ControllerContext
* @internal only to be used within Extbase, not part of TYPO3 Core API.
*/
protected $controllerContext;
......@@ -215,7 +215,7 @@ abstract class ActionController implements ControllerInterface
/**
* Injects the object manager
*
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
* @param ObjectManagerInterface $objectManager
* @internal only to be used within Extbase, not part of TYPO3 Core API.
*/
public function injectObjectManager(ObjectManagerInterface $objectManager)
......@@ -396,11 +396,11 @@ abstract class ActionController implements ControllerInterface
// todo: It's quite odd that an instance of ConjunctionValidator is created directly here.
// todo: \TYPO3\CMS\Extbase\Validation\ValidatorResolver::getBaseValidatorConjunction could/should be used
// todo: here, to benefit of the built in 1st level cache of the ValidatorResolver.
$validator = $this->objectManager->get(ConjunctionValidator::class);
$validator = GeneralUtility::makeInstance(ConjunctionValidator::class);
foreach ($classSchemaMethodParameter->getValidators() as $validatorDefinition) {
/** @var ValidatorInterface $validatorInstance */
$validatorInstance = $this->objectManager->get(
$validatorInstance = GeneralUtility::makeInstance(
$validatorDefinition['className'],
$validatorDefinition['options']
);
......@@ -449,7 +449,7 @@ abstract class ActionController implements ControllerInterface
$this->request = $request;
// @deprecated since v11, will be removed in v12.
$this->request->setDispatched(true);
$this->uriBuilder = $this->objectManager->get(UriBuilder::class);
$this->uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
$this->uriBuilder->setRequest($request);
$this->actionMethodName = $this->resolveActionMethodName();
$this->initializeActionMethodArguments();
......@@ -621,7 +621,7 @@ abstract class ActionController implements ControllerInterface
}
}
if (!isset($view)) {
$view = $this->objectManager->get(NotFoundView::class);
$view = GeneralUtility::makeInstance(NotFoundView::class);
$view->assign('errorMessage', 'No template was found. View could not be resolved for action "'
. $this->request->getControllerActionName() . '" in class "' . $this->request->getControllerObjectName() . '"');
}
......@@ -878,14 +878,14 @@ abstract class ActionController implements ControllerInterface
/**
* Initialize the controller context
*
* @return \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext ControllerContext to be passed to the view
* @return ControllerContext ControllerContext to be passed to the view
*
* @internal only to be used within Extbase, not part of TYPO3 Core API.
*/
protected function buildControllerContext()
{
/** @var \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext $controllerContext */
$controllerContext = $this->objectManager->get(ControllerContext::class);
/** @var ControllerContext $controllerContext */
$controllerContext = GeneralUtility::makeInstance(ControllerContext::class);
$controllerContext->setRequest($this->request);
if ($this->arguments !== null) {
$controllerContext->setArguments($this->arguments);
......
......@@ -19,7 +19,6 @@ use TYPO3\CMS\Core\Messaging\FlashMessageService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Request;
use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Service\ExtensionService;
/**
......@@ -38,7 +37,7 @@ class ControllerContext
protected $arguments;
/**
* @var \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder
* @var UriBuilder
*/
protected $uriBuilder;
......@@ -114,7 +113,7 @@ class ControllerContext
}
/**
* @param \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder $uriBuilder
* @param UriBuilder $uriBuilder
*/
public function setUriBuilder(UriBuilder $uriBuilder)
{
......@@ -122,7 +121,7 @@ class ControllerContext
}
/**
* @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder
* @return UriBuilder
* @deprecated since v11, will be removed in v12
*/
public function getUriBuilder()
......@@ -130,7 +129,7 @@ class ControllerContext
// todo: trigger an error as soon as this whole object can be deprecated
if (!$this->uriBuilder) {
$this->uriBuilder = GeneralUtility::makeInstance(ObjectManager::class)->get(UriBuilder::class);
$this->uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
if ($this->request) {
$this->uriBuilder->setRequest($this->request);
}
......
......@@ -130,6 +130,7 @@ class Dispatcher implements SingletonInterface
if ($this->container->has($controllerObjectName)) {
$controller = $this->container->get($controllerObjectName);
} else {
// @deprecated since v11, will be removed in v12.
$controller = $this->objectManager->get($controllerObjectName);
}
if (!$controller instanceof ControllerInterface) {
......
......@@ -17,6 +17,8 @@ declare(strict_types=1);
namespace TYPO3\CMS\Extbase\Mvc\View;
use Psr\Container\ContainerInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
/**
......@@ -24,19 +26,16 @@ use TYPO3\CMS\Extbase\Object\ObjectManager;
*/
class GenericViewResolver implements ViewResolverInterface
{
/**
* @var ObjectManager
*/
private $objectManager;
private ContainerInterface $container;
/**
* @var string
*/
private $defaultViewClass;
public function __construct(ObjectManager $objectManager)
public function __construct(ContainerInterface $container)
{
$this->objectManager = $objectManager;
$this->container = $container;
}
/**
......@@ -50,6 +49,14 @@ class GenericViewResolver implements ViewResolverInterface
public function resolve(string $controllerObjectName, string $actionName, string $format): ViewInterface
{
return $this->objectManager->get($this->defaultViewClass);
if ($this->container->has($this->defaultViewClass)) {
/** @var ViewInterface $view */
$view = $this->container->get($this->defaultViewClass);
return $view;
}
// @deprecated since v11, will be removed with 12. Fallback if extensions provide no proper Services.yaml. Drop together with if condition above in v12.
/** @var ViewInterface $view */
$view = GeneralUtility::makeInstance(ObjectManager::class)->get($this->defaultViewClass);
return $view;
}
}
<?php
/*
* 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\Persistence;
/**
* Helper interface for v11 DI to see if a Query can be autowired,
* or if a fallback to ObjectManager needs to be done.
*
* @deprecated since v11, will be merged into QueryInterface in v12.
*/
interface ForwardCompatibleQueryInterface extends QueryInterface
{
public function setType(string $type): void;
}
<?php
/*
* 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\Persistence;
/**
* Helper interface for v11 DI to see if a QueryResult can be autowired,
* or if a fallback to ObjectManager needs to be done.
*
* @deprecated since v11, will be merged into QueryResultInterface in v12.
*/
interface ForwardCompatibleQueryResultInterface extends QueryResultInterface
{
public function setQuery(QueryInterface $query): void;
}
......@@ -15,9 +15,9 @@
namespace TYPO3\CMS\Extbase\Persistence\Generic;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject;
use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface;
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
/**
......@@ -27,10 +27,7 @@ use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
*/
class LazyLoadingProxy implements \Iterator, LoadingStrategyInterface
{
/**
* @var DataMapper|null
*/
protected $dataMapper;
protected DataMapper $dataMapper;
/**
* The object this property is contained in.
......@@ -53,19 +50,6 @@ class LazyLoadingProxy implements \Iterator, LoadingStrategyInterface
*/
private $fieldValue;
/**
* @var ObjectManagerInterface
*/
protected $objectManager;
/**
* @param ObjectManagerInterface $objectManager
*/
public function injectObjectManager(ObjectManagerInterface $objectManager)
{
$this->objectManager = $objectManager;
}
/**
* Constructs this proxy instance.
*
......@@ -79,17 +63,11 @@ class LazyLoadingProxy implements \Iterator, LoadingStrategyInterface
$this->parentObject = $parentObject;
$this->propertyName = $propertyName;
$this->fieldValue = $fieldValue;
$this->dataMapper = $dataMapper;
}
/**
* Object initialization called when object is created with ObjectManager, after constructor
*/
public function initializeObject()
{
if (!$this->dataMapper) {
$this->dataMapper = $this->objectManager->get(DataMapper::class);
if ($dataMapper === null) {
$dataMapper = GeneralUtility::makeInstance(DataMapper::class);
}
/** @var DataMapper $dataMapper */
$this->dataMapper = $dataMapper;
}
/**
......
......@@ -15,7 +15,8 @@
namespace TYPO3\CMS\Extbase\Persistence\Generic;
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
use Symfony\Component\VarDumper\Cloner\Data;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
......@@ -40,10 +41,7 @@ class LazyObjectStorage extends ObjectStorage implements LoadingStrategyInterfac
*/
private $warning = 'You should never see this warning. If you do, you probably used PHP array functions like current() on the TYPO3\\CMS\\Extbase\\Persistence\\Generic\\LazyObjectStorage. To retrieve the first result, you can use the rewind() and current() methods.';
/**
* @var DataMapper|null
*/
protected $dataMapper;
protected DataMapper $dataMapper;
/**
* The object this property is contained in.
......@@ -71,19 +69,6 @@ class LazyObjectStorage extends ObjectStorage implements LoadingStrategyInterfac
*/
protected $isInitialized = false;
/**
* @var ObjectManagerInterface
*/
protected $objectManager;
/**
* @param ObjectManagerInterface $objectManager
*/
public function injectObjectManager(ObjectManagerInterface $objectManager)
{
$this->objectManager = $objectManager;
}
/**
* Returns the state of the initialization
*
......@@ -108,17 +93,11 @@ class LazyObjectStorage extends ObjectStorage implements LoadingStrategyInterfac
$this->propertyName = $propertyName;
$this->fieldValue = $fieldValue;
reset($this->storage);
$this->dataMapper = $dataMapper;
}
/**
* Object initialization called when object is created with ObjectManager, after constructor
*/
public function initializeObject()
{
if (!$this->dataMapper) {
$this->dataMapper = $this->objectManager->get(DataMapper::class);
if ($dataMapper === null) {
$dataMapper = GeneralUtility::makeInstance(DataMapper::class);
}
/** @var DataMapper $dataMapper */
$this->dataMapper = $dataMapper;
}
/**
......
......@@ -48,56 +48,19 @@ use TYPO3\CMS\Extbase\Utility\TypeHandlingUtility;
*/
class DataMapper
{
/**
* @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
*/
protected $reflectionService;
/**
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory
*/
protected $qomFactory;
/**
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Session
*/
protected $persistenceSession;
/**
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory
*/
protected $dataMapFactory;
/**
* @var \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface
*/
protected $queryFactory;
/**
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
*/
protected $objectManager;
/**
* @var EventDispatcherInterface
*/
protected $eventDispatcher;
protected ReflectionService $reflectionService;
protected QueryObjectModelFactory $qomFactory;
protected Session $persistenceSession;
protected DataMapFactory $dataMapFactory;
protected QueryFactoryInterface $queryFactory;
protected ObjectManagerInterface $objectManager;
protected EventDispatcherInterface $eventDispatcher;
/**
* @var QueryInterface|null
*/
protected $query;
/**
* DataMapper constructor.
* @param \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Session $persistenceSession
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory $dataMapFactory
* @param \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface $queryFactory
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
* @param EventDispatcherInterface $eventDispatcher
*/
public function __construct(
ReflectionService $reflectionService,
QueryObjectModelFactory $qomFactory,
......@@ -112,6 +75,7 @@ class DataMapper
$this->persistenceSession = $persistenceSession;
$this->dataMapFactory = $dataMapFactory;
$this->queryFactory = $queryFactory;
// @deprecated since v11, will be removed in v12.
$this->objectManager = $objectManager;
$this->eventDispatcher = $eventDispatcher;
}
......@@ -367,12 +331,12 @@ class DataMapper
$property = $this->reflectionService->getClassSchema(get_class($parentObject))->getProperty($propertyName);
if ($enableLazyLoading === true && $property->isLazy()) {
if ($property->getType() === ObjectStorage::class) {
$result = $this->objectManager->get(LazyObjectStorage::class, $parentObject, $propertyName, $fieldValue, $this);
$result = GeneralUtility::makeInstance(LazyObjectStorage::class, $parentObject, $propertyName, $fieldValue, $this);
} else {
if (empty($fieldValue)) {
$result = null;
} else {
$result = $this->objectManager->get(LazyLoadingProxy::class, $parentObject, $propertyName, $fieldValue, $this);
$result = GeneralUtility::makeInstance(LazyLoadingProxy::class, $parentObject, $propertyName, $fieldValue, $this);
}
}
} else {
......
......@@ -15,9 +15,11 @@
namespace TYPO3\CMS\Extbase\Persistence\Generic;
use Psr\Container\ContainerInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
use TYPO3\CMS\Extbase\Persistence\ForwardCompatibleQueryInterface;
use TYPO3\CMS\Extbase\Persistence\ForwardCompatibleQueryResultInterface;
use TYPO3\CMS\Extbase\Persistence\Generic\Exception\InvalidNumberOfConstraintsException;
use TYPO3\CMS\Extbase\Persistence\Generic\Exception\UnexpectedTypeException;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory;
......@@ -32,8 +34,11 @@ use TYPO3\CMS\Extbase\Utility\TypeHandlingUtility;
/**
* The Query class used to run queries against the database
*
* @todo v12: Drop ForwardCompatibleQueryInterface when merged into QueryInterface
* @todo v12: Candidate to declare final - Can be decorated or standalone class implementing the interface
*/
class Query implements QueryInterface
class Query implements QueryInterface, ForwardCompatibleQueryInterface
{
/**
* An inner join.
......@@ -60,25 +65,10 @@ class Query implements QueryInterface
*/
protected $type;
/**
* @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
*/
protected $objectManager;
/**
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory
*/
protected $dataMapFactory;
/**
* @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
*/
protected $persistenceManager;
/**
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory
*/
protected $qomFactory;
protected DataMapFactory $dataMapFactory;
protected PersistenceManagerInterface $persistenceManager;
protected QueryObjectModelFactory $qomFactory;
protected ContainerInterface $container;
/**
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Qom\SourceInterface
......@@ -123,44 +113,19 @@ class Query implements QueryInterface
*/
protected $parentQuery;
/**
* @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
*/
public function injectObjectManager(ObjectManagerInterface $objectManager)
{
$this->objectManager = $objectManager;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory $dataMapFactory
*/
public function injectDataMapFactory(DataMapFactory $dataMapFactory)
{
public function __construct(
DataMapFactory $dataMapFactory,
PersistenceManagerInterface $persistenceManager,
QueryObjectModelFactory $qomFactory,
ContainerInterface $container
) {
$this->dataMapFactory = $dataMapFactory;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager
*/
public function injectPersistenceManager(PersistenceManagerInterface $persistenceManager)
{
$this->persistenceManager = $persistenceManager;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory $qomFactory
*/
public function injectQomFactory(QueryObjectModelFactory $qomFactory)
{
$this->qomFactory = $qomFactory;
$this->container = $container;
}
/**
* Constructs a query object working on the given class name
*
* @param string $type
*/
public function __construct($type)
public function setType(string $type): void
{
$this->type = $type;
}
......@@ -260,14 +225,25 @@ class Query implements QueryInterface
* Executes the query against the database and returns the result
*
* @param bool $returnRawQueryResult avoids the object mapping by the persistence
* @return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface|array The query result object or an array if $returnRawQueryResult is TRUE
* @return QueryResultInterface|array The query result object or an array if $returnRawQueryResult is TRUE
*/
public function execute($returnRawQueryResult = false)
{
if ($returnRawQueryResult) {
return $this->persistenceManager->getObjectDataByQuery($this);
}
return $this->objectManager->get(QueryResultInterface::class, $this);
if ($this->container->has(QueryResultInterface::class)) {
/** @var QueryResultInterface $queryResult */
$queryResult = $this->container->get(QueryResultInterface::class);
if ($queryResult instanceof ForwardCompatibleQueryResultInterface) {
$queryResult->setQuery($this);
return $queryResult;
}
}
// @deprecated since v11, will be removed in v12. Fallback to ObjectManager, drop together with ForwardCompatibleQueryResultInterface.
/** @var QueryResultInterface $queryResult */
$queryResult = GeneralUtility::makeInstance(ObjectManager::class)->get(QueryResultInterface::class, $this);
return $queryResult;
}
/**
......@@ -619,10 +595,9 @@ class Query implements QueryInterface
*/
public function __wakeup()
{
$this->objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$this->persistenceManager = $this->objectManager->get(PersistenceManagerInterface::class);
$this->dataMapFactory = $this->objectManager->get(DataMapFactory::class);
$this->qomFactory = $this->objectManager->get(QueryObjectModelFactory::class);
$this->persistenceManager = GeneralUtility::makeInstance(PersistenceManagerInterface::class);
$this->dataMapFactory = GeneralUtility::makeInstance(DataMapFactory::class);
$this->qomFactory = GeneralUtility::makeInstance(QueryObjectModelFactory::class);
}
/**
......