Epic #82404

Improve enumeration usage

Added by Romain Canon over 1 year ago. Updated 3 months ago.

Status:
Under Review
Priority:
Should have
Assignee:
Category:
-
Start date:
2017-09-09
Due date:
% Done:

0%

Sprint Focus:

Description

TL;DR - Improve the enumeration feature to have something more similar to this implementation: https://github.com/myclabs/php-enum

Current usage

The current core enumeration implementations mainly work with string values and do not force types in any way. This can lead to incorrect values being used by functions and lead to more runtime errors.

See below some basic usage taken in current core master, and comments about what is wrong with them:

// Doubling type casting + duplicated class name
(int)(string)new VersionState(VersionState::DEFAULT_STATE)
// Duplicated class name + useless instance (could be only string comparison)
switch (VersionState::cast($row['t3ver_state'])) {
    case new VersionState(VersionState::NEW_PLACEHOLDER):
        $parts[] = 'PLH WSID#' . $row['t3ver_wsid'];
        break;
}

// A string is passed in `$conflictMode`.
//
// This should not be the responsability of the method `rename()`
// to validate and cast the value that is passed, but to the
// method that actually calls `rename()`.
//
// This can lead to more errors if not handled correctly.
public function rename($newName, $conflictMode = DuplicationBehavior::RENAME)

Goal

The main goal of the patch would be to use enumerations as value objects, which allows a much more stronger and bug-free application, as well as more flexibility in how data can be used. This also helps with onboarding new contributors who can understand the logic behind a function much more easily.


The current enumeration class (\TYPO3\CMS\Core\Type\Enumeration) would be improved.

Magic method calls

One of the new introduced features would be magic static methods calls, to dramatically ease readability:

// Old way:
$myEnum = MyEnum::cast(MyEnum::MY_VALUE);

// New way:
$myEnum = MyEnum::MY_VALUE();

Data mapping

The data mapper automatically fills enum values, which means a frontend form being submitted can then create a PHP object containing enum values, which is awesome when you actually have to work with the object.

Utility methods

Enumeration classes should use more utility functions to ease the usage when working with implementation.

TYPO3 core already uses this kind of methods (see TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus::isGreaterThan()), but there could be much more.

Example

See below an implementation example of how TYPO3 page types could be handled:

// The actual enumeration class.
class PageType extends Enumeration
{
    // Pages
    const STANDARD = 1;
    const BACKEND_USER_SECTION = 6;

    // Links
    const SHORTCUT = 4;
    const MOUNT_POINT = 7;
    const EXTERNAL_URL = 3;

    // Special
    const FOLDER = 254;
    const RECYCLER = 255;
    const MENU_SEPARATOR = 199;

    /**
     * Will be true if the type is one of the links types.
     *
     * @return bool
     */
    public function isLink(): bool
    {
        return $this->equal(static::SHORTCUT())
            || $this->equal(static::MOUNT_POINT())
            || $this->equal(static::EXTERNAL_URL());
    }

    /**
     * Will be true only if the type is folder, false in any other case.
     *
     * @return bool
     */
    public function isFolder(): bool
    {
        return $this->equals(static::FOLDER());
    }
}

// A class using the enumeration.
class Page 
{
    /**
     * @var PageType
     */
    protected $type;

    /**
     * @param PageType $type
     */
    public function setType(PageType $type)
    {
        $this->type = $type;
    }

    /**
     * @return PageType
     */
    public function getType()
    {
        return $this->type;
    }
}

// Basic usage.
class MyClass
{
    public function process()
    {
        $page = new Page;
        $page->setType(PageType::STANDARD());

        // ...

        $this->doSomething($page);        
    }

    /**
     * @param Page $page
     */
    protected function doSomething(Page $page)
    {
        if ($page->getType()->isFolder()) {
            // Do folder related things...
        } elseif ($page->getType()->isLink()) {
            // Create some link...
        } elseif ($page->getType()->equals(PageType::STANDARD())) {
            // ...
        } else {
            // ...
        }
    }
}

Please note that this whole implementation has already been done and used in my company for a whole year now, using this tiny library: https://github.com/myclabs/php-enum

Every developer uses it almost every day and everyone did say this improved productivity, code understanding and application reliability by a lot, compared to an old string-comparison way.


Subtasks

Task #82411: Breaking: refactor enumeration classUnder ReviewRomain Canon

Feature #82412: Add magic static call to enumeration classNewRomain Canon

Task #82413: Change enumeration usage in coreNewRomain Canon

History

#1 Updated by Romain Canon over 1 year ago

  • Tracker changed from Feature to Task
  • TYPO3 Version set to 9

#2 Updated by Gerrit Code Review over 1 year ago

  • Status changed from New to Under Review

Patch set 1 for branch master of project Packages/TYPO3.CMS has been pushed to the review server.
It is available at https://review.typo3.org/54064

#3 Updated by Romain Canon over 1 year ago

  • Tracker changed from Task to Epic

#4 Updated by Romain Canon over 1 year ago

  • Sprint Focus deleted (On Location Sprint)

#5 Updated by Susanne Moog 3 months ago

  • Target version changed from 9 LTS to Candidate for Major Version

Also available in: Atom PDF