Commit 3c78adc6 authored by Christian Kuhn's avatar Christian Kuhn
Browse files

[TASK] Deprecate generic extbase domain classes

Extbase provides a couple of generic domain repositories
and models, especially frontend / backend users and
groups. Those are flawed by design:

The main issue is that domain models have to be specific
for the domain they are used in. By definition, a generic,
opinionated model can't be "correct" since the domain
it is used in, is unique: It might be that a backend user
email has to be set and the domain does not model
anything but email and firstname?

Many usages don't need backend groups attached to a
backend user model at all, or if they need them, then
maybe in a recursive presentation, or a specific order
or something similar. Having a default group resolution
is thus at least misleading, if not wrong, and can be a
performance issue on top.

A generic model can never foresee its usages. The existing
models thus try to 1:1 adapt the database fields, which
is also misleading since a domain model is not and should
not be a direct representation of a database table. It
would only be by chance if the generic models fit a
specific domain.

Similar issues exist with the repositories: The
CategoryRepository for instance assumes it is a good
idea to set respectStoragePid(false), which is most
likely not the right thing for an extension use.
In the end, whatever extbase delivers here, is most
likely wrong and does not fit the problem domain.

The patch keeps the 'experimental' FAL related models
since those can be actually useful for extensions and
their final fate has not been decided, yet. The other
generic models, especially those with lots of properties
are marked as deprecated with the patch.

Change-Id: I06629fddd0258c517f3fa8bdf2e9c4b342be9678
Resolves: #94654
Related: #83296
Releases: master
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/70061

Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Tested-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Reviewed-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
parent 1e7653ce
...@@ -18,7 +18,6 @@ namespace TYPO3\CMS\Beuser\ViewHelpers; ...@@ -18,7 +18,6 @@ namespace TYPO3\CMS\Beuser\ViewHelpers;
use TYPO3\CMS\Core\Imaging\Icon; use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory; use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Domain\Model\BackendUser;
use TYPO3\CMS\Fluid\ViewHelpers\Be\AbstractBackendViewHelper; use TYPO3\CMS\Fluid\ViewHelpers\Be\AbstractBackendViewHelper;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface; use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
...@@ -83,16 +82,12 @@ class SpriteIconForRecordViewHelper extends AbstractBackendViewHelper ...@@ -83,16 +82,12 @@ class SpriteIconForRecordViewHelper extends AbstractBackendViewHelper
if (method_exists($object, 'getHidden')) { if (method_exists($object, 'getHidden')) {
$row['hidden'] = $object->getHidden(); $row['hidden'] = $object->getHidden();
} }
if ($table === 'be_users' && $object instanceof BackendUser) {
$row['admin'] = $object->getIsAdministrator();
}
if (method_exists($object, 'getStartDateAndTime')) { if (method_exists($object, 'getStartDateAndTime')) {
$row['startTime'] = $object->getStartDateAndTime(); $row['startTime'] = $object->getStartDateAndTime();
} }
if (method_exists($object, 'getEndDateAndTime')) { if (method_exists($object, 'getEndDateAndTime')) {
$row['endTime'] = $object->getEndDateAndTime(); $row['endTime'] = $object->getEndDateAndTime();
} }
/** @var IconFactory $iconFactory */
$iconFactory = GeneralUtility::makeInstance(IconFactory::class); $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
return $iconFactory->getIconForRecord($table, $row, Icon::SIZE_SMALL)->render(); return $iconFactory->getIconForRecord($table, $row, Icon::SIZE_SMALL)->render();
} }
......
.. include:: ../../Includes.txt
====================================================
Deprecation: #94654 - Generic extbase domain classes
====================================================
See :issue:`94654`
Description
===========
Most extbase "generic" domain model and repositories have been deprecated:
They are opinionated implementations and can't be "correct" since the
domains they are used in, are unique.
The following classes have been deprecated:
* :php:`TYPO3\CMS\Extbase\Domain\Model\BackendUser`
* :php:`TYPO3\CMS\Extbase\Domain\Model\BackendUserGroup`
* :php:`TYPO3\CMS\Extbase\Domain\Model\FrontendUser`
* :php:`TYPO3\CMS\Extbase\Domain\Model\FrontendUserGroup`
* :php:`TYPO3\CMS\Extbase\Domain\Repository\BackendUserGroupRepository`
* :php:`TYPO3\CMS\Extbase\Domain\Repository\BackendUserRepository`
* :php:`TYPO3\CMS\Extbase\Domain\Repository\CategoryRepository`
* :php:`TYPO3\CMS\Extbase\Domain\Repository\FrontendUserGroupRepository`
* :php:`TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository`
Impact
======
Using or extending the above classes is deprecated since core v11.
They will be removed with core v12.
Affected Installations
======================
Various extbase based extensions may use or extend the classes. The
extension scanner will find usages with a strong match.
Migration
=========
The migration paths are usually straight forward.
Extensions that extend the repository classes should extend extbase
:php:`TYPO3\CMS\Extbase\Persistence\Repository` instead and maybe copy
body methods like :php:`initializeObject()` if given and not overridden
already.
Extensions that use the extbase repositories directly should copy the
class to their extension namespace and use the own ones instead.
Extensions that extend the model classes should extend
:php:`TYPO3\CMS\Extbase\DomainObject\AbstractEntity` instead and copy
the properties, getters and setters they need from the extbase classes.
Those copied properties may need database mapping entries, which can
be copied from :file:`EXT:extbase/Configuration/Extbase/Persistence/Classes.php`.
Extensions that use the extbase models directly should copy the class
to their extension namespace, ideally strip them down to what the extension
actually needs, and copy the needed mapping information from
:file:`EXT:extbase/Configuration/Extbase/Persistence/Classes.php`.
No database update of existing rows should be needed when transferring
the models to an own namespace, since none of the extbase models
configured a :php:`recordType` in the mapping file at
:file:`EXT:extbase/Configuration/Extbase/Persistence/Classes.php`.
.. index:: PHP-API, FullyScanned, ext:extbase
...@@ -20,6 +20,8 @@ use TYPO3\CMS\Extbase\DomainObject\AbstractEntity; ...@@ -20,6 +20,8 @@ use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
/** /**
* This model represents a back-end user. * This model represents a back-end user.
*
* @deprecated since v11, will be removed in v12. Do not use or extend this model.
*/ */
class BackendUser extends AbstractEntity class BackendUser extends AbstractEntity
{ {
......
...@@ -21,6 +21,8 @@ use TYPO3\CMS\Extbase\Persistence\ObjectStorage; ...@@ -21,6 +21,8 @@ use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
/** /**
* This model represents a backend usergroup. * This model represents a backend usergroup.
*
* @deprecated since v11, will be removed in v12. Do not use or extend this model.
*/ */
class BackendUserGroup extends AbstractEntity class BackendUserGroup extends AbstractEntity
{ {
......
...@@ -36,7 +36,7 @@ class Category extends AbstractEntity ...@@ -36,7 +36,7 @@ class Category extends AbstractEntity
protected $description = ''; protected $description = '';
/** /**
* @var \TYPO3\CMS\Extbase\Domain\Model\Category|null * @var Category|null
* @Extbase\ORM\Lazy * @Extbase\ORM\Lazy
*/ */
protected $parent; protected $parent;
...@@ -84,7 +84,7 @@ class Category extends AbstractEntity ...@@ -84,7 +84,7 @@ class Category extends AbstractEntity
/** /**
* Gets the parent category. * Gets the parent category.
* *
* @return \TYPO3\CMS\Extbase\Domain\Model\Category|null the parent category * @return Category|null the parent category
*/ */
public function getParent() public function getParent()
{ {
...@@ -97,9 +97,9 @@ class Category extends AbstractEntity ...@@ -97,9 +97,9 @@ class Category extends AbstractEntity
/** /**
* Sets the parent category. * Sets the parent category.
* *
* @param \TYPO3\CMS\Extbase\Domain\Model\Category $parent the parent category * @param Category $parent the parent category
*/ */
public function setParent(\TYPO3\CMS\Extbase\Domain\Model\Category $parent) public function setParent(Category $parent)
{ {
$this->parent = $parent; $this->parent = $parent;
} }
......
...@@ -20,6 +20,8 @@ use TYPO3\CMS\Extbase\Persistence\ObjectStorage; ...@@ -20,6 +20,8 @@ use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
/** /**
* A Frontend User * A Frontend User
*
* @deprecated since v11, will be removed in v12. Do not use or extend this model.
*/ */
class FrontendUser extends AbstractEntity class FrontendUser extends AbstractEntity
{ {
......
...@@ -20,6 +20,8 @@ use TYPO3\CMS\Extbase\Persistence\ObjectStorage; ...@@ -20,6 +20,8 @@ use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
/** /**
* A Frontend User Group * A Frontend User Group
*
* @deprecated since v11, will be removed in v12. Do not use or extend this model.
*/ */
class FrontendUserGroup extends AbstractEntity class FrontendUserGroup extends AbstractEntity
{ {
......
...@@ -23,6 +23,8 @@ use TYPO3\CMS\Extbase\Persistence\Repository; ...@@ -23,6 +23,8 @@ use TYPO3\CMS\Extbase\Persistence\Repository;
/** /**
* Repository for \TYPO3\CMS\Extbase\Domain\Model\BackendUserGroup. * Repository for \TYPO3\CMS\Extbase\Domain\Model\BackendUserGroup.
*
* @deprecated since v11, will be removed in v12. Do not use or extend this model.
*/ */
class BackendUserGroupRepository extends Repository class BackendUserGroupRepository extends Repository
{ {
......
...@@ -23,6 +23,8 @@ use TYPO3\CMS\Extbase\Persistence\Repository; ...@@ -23,6 +23,8 @@ use TYPO3\CMS\Extbase\Persistence\Repository;
/** /**
* Repository for \TYPO3\CMS\Extbase\Domain\Model\BackendUser. * Repository for \TYPO3\CMS\Extbase\Domain\Model\BackendUser.
*
* @deprecated since v11, will be removed in v12. Do not use or extend this model.
*/ */
class BackendUserRepository extends Repository class BackendUserRepository extends Repository
{ {
......
...@@ -23,6 +23,8 @@ use TYPO3\CMS\Extbase\Persistence\Repository; ...@@ -23,6 +23,8 @@ use TYPO3\CMS\Extbase\Persistence\Repository;
/** /**
* Repository for Category models. * Repository for Category models.
*
* @deprecated since v11, will be removed in v12. Do not use or extend this model.
*/ */
class CategoryRepository extends Repository class CategoryRepository extends Repository
{ {
......
...@@ -21,6 +21,8 @@ use TYPO3\CMS\Extbase\Persistence\Repository; ...@@ -21,6 +21,8 @@ use TYPO3\CMS\Extbase\Persistence\Repository;
/** /**
* A Frontend User Group Repository * A Frontend User Group Repository
*
* @deprecated since v11, will be removed in v12. Do not use or extend this model.
*/ */
class FrontendUserGroupRepository extends Repository class FrontendUserGroupRepository extends Repository
{ {
......
...@@ -21,6 +21,8 @@ use TYPO3\CMS\Extbase\Persistence\Repository; ...@@ -21,6 +21,8 @@ use TYPO3\CMS\Extbase\Persistence\Repository;
/** /**
* A Frontend User repository * A Frontend User repository
*
* @deprecated since v11, will be removed in v12. Do not use or extend this model.
*/ */
class FrontendUserRepository extends Repository class FrontendUserRepository extends Repository
{ {
......
...@@ -9,6 +9,7 @@ return [ ...@@ -9,6 +9,7 @@ return [
\TYPO3\CMS\Extbase\Domain\Model\File::class => [ \TYPO3\CMS\Extbase\Domain\Model\File::class => [
'tableName' => 'sys_file', 'tableName' => 'sys_file',
], ],
// @deprecated since v11, will be removed in v12.
\TYPO3\CMS\Extbase\Domain\Model\BackendUser::class => [ \TYPO3\CMS\Extbase\Domain\Model\BackendUser::class => [
'tableName' => 'be_users', 'tableName' => 'be_users',
'properties' => [ 'properties' => [
...@@ -35,6 +36,7 @@ return [ ...@@ -35,6 +36,7 @@ return [
], ],
], ],
], ],
// @deprecated since v11, will be removed in v12.
\TYPO3\CMS\Extbase\Domain\Model\BackendUserGroup::class => [ \TYPO3\CMS\Extbase\Domain\Model\BackendUserGroup::class => [
'tableName' => 'be_groups', 'tableName' => 'be_groups',
'properties' => [ 'properties' => [
...@@ -76,9 +78,11 @@ return [ ...@@ -76,9 +78,11 @@ return [
], ],
], ],
], ],
// @deprecated since v11, will be removed in v12.
\TYPO3\CMS\Extbase\Domain\Model\FrontendUser::class => [ \TYPO3\CMS\Extbase\Domain\Model\FrontendUser::class => [
'tableName' => 'fe_users', 'tableName' => 'fe_users',
], ],
// @deprecated since v11, will be removed in v12.
\TYPO3\CMS\Extbase\Domain\Model\FrontendUserGroup::class => [ \TYPO3\CMS\Extbase\Domain\Model\FrontendUserGroup::class => [
'tableName' => 'fe_groups', 'tableName' => 'fe_groups',
], ],
......
...@@ -15,11 +15,532 @@ ...@@ -15,11 +15,532 @@
namespace ExtbaseTeam\BlogExample\Domain\Model; namespace ExtbaseTeam\BlogExample\Domain\Model;
use TYPO3\CMS\Extbase\Domain\Model\FrontendUser; use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
/** /**
* An Administrator of a Blog * An Administrator of a Blog
*/ */
class Administrator extends FrontendUser class Administrator extends AbstractEntity
{ {
/**
* @var string
*/
protected $username = '';
/**
* @var string
*/
protected $password = '';
/**
* @var ObjectStorage<FrontendUserGroup>
*/
protected $usergroup;
/**
* @var string
*/
protected $name = '';
/**
* @var string
*/
protected $firstName = '';
/**
* @var string
*/
protected $middleName = '';
/**
* @var string
*/
protected $lastName = '';
/**
* @var string
*/
protected $address = '';
/**
* @var string
*/
protected $telephone = '';
/**
* @var string
*/
protected $fax = '';
/**
* @var string
*/
protected $email = '';
/**
* @var string
*/
protected $title = '';
/**
* @var string
*/
protected $zip = '';
/**
* @var string
*/
protected $city = '';
/**
* @var string
*/
protected $country = '';
/**
* @var string
*/
protected $www = '';
/**
* @var string
*/
protected $company = '';
/**
* @var ObjectStorage<FileReference>
*/
protected $image;
/**
* @var \DateTime|null
*/
protected $lastlogin;
/**
* Constructs a new Front-End User
*
* @param string $username
* @param string $password
*/
public function __construct($username = '', $password = '')
{
$this->username = $username;
$this->password = $password;
$this->usergroup = new ObjectStorage();
$this->image = new ObjectStorage();
}
/**
* Called again with initialize object, as fetching an entity from the DB does not use the constructor
*/
public function initializeObject()
{
$this->usergroup = $this->usergroup ?? new ObjectStorage();
$this->image = $this->image ?? new ObjectStorage();
}
/**
* Sets the username value
*
* @param string $username
*/
public function setUsername($username)
{
$this->username = $username;
}
/**
* Returns the username value
*
* @return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Sets the password value
*
* @param string $password
*/
public function setPassword($password)
{
$this->password = $password;
}
/**
* Returns the password value
*
* @return string
*/
public function getPassword()
{
return $this->password;
}
/**
* Sets the usergroups. Keep in mind that the property is called "usergroup"
* although it can hold several usergroups.
*
* @param ObjectStorage<FrontendUserGroup> $usergroup
*/
public function setUsergroup(ObjectStorage $usergroup)
{
$this->usergroup = $usergroup;
}
/**
* Adds a usergroup to the frontend user
*
* @param FrontendUserGroup $usergroup
*/
public function addUsergroup(FrontendUserGroup $usergroup)
{
$this->usergroup->attach($usergroup);
}
/**
* Removes a usergroup from the frontend user
*
* @param FrontendUserGroup $usergroup
*/
public function removeUsergroup(FrontendUserGroup $usergroup)
{
$this->usergroup->detach($usergroup);
}
/**
* Returns the usergroups. Keep in mind that the property is called "usergroup"
* although it can hold several usergroups.
*
* @return ObjectStorage<FrontendUserGroup> An object storage containing the usergroup
*/
public function getUsergroup()
{
return $this->usergroup;
}
/**
* Sets the name value
*
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Returns the name value
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Sets the firstName value
*