From ccbbe900b38b008d5829f9da1b3973445e4115cc Mon Sep 17 00:00:00 2001
From: Oliver Klee <typo3-coding@oliverklee.de>
Date: Mon, 18 Apr 2022 16:13:35 +0200
Subject: [PATCH] [BUGFIX] Allow XCLASSing of WorkspaceRecord
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The factory method WorkspaceRecord::get() now uses a proper
makeInstance() call instead of new for creating new instances,
which allows XCLASSing the class and aligns object creation
to "the TYPO3 way" in that place.

Also add a regression test.

Resolves: #97423
Relates: #97754
Releases: main, 11.5
Change-Id: I76e5ce3a1f908bf0efa4faaa439724e2d1d7cbb2
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/74960
Tested-by: core-ci <typo3@b13.com>
Tested-by: Stefan Bürk <stefan@buerk.tech>
Reviewed-by: Stefan Bürk <stefan@buerk.tech>
---
 Build/phpstan/phpstan-baseline.neon           |  5 -
 .../Classes/Domain/Record/WorkspaceRecord.php |  5 +-
 .../Unit/Domain/Model/WorkspaceRecordTest.php | 99 +++++++++++++++++++
 3 files changed, 101 insertions(+), 8 deletions(-)
 create mode 100644 typo3/sysext/workspaces/Tests/Unit/Domain/Model/WorkspaceRecordTest.php

diff --git a/Build/phpstan/phpstan-baseline.neon b/Build/phpstan/phpstan-baseline.neon
index d09ba1ee9c26..8167cbc2c196 100644
--- a/Build/phpstan/phpstan-baseline.neon
+++ b/Build/phpstan/phpstan-baseline.neon
@@ -5385,11 +5385,6 @@ parameters:
 			count: 1
 			path: ../../typo3/sysext/workspaces/Classes/Controller/PreviewController.php
 
-		-
-			message: "#^Unsafe usage of new static\\(\\)\\.$#"
-			count: 1
-			path: ../../typo3/sysext/workspaces/Classes/Domain/Record/WorkspaceRecord.php
-
 		-
 			message: "#^Offset 0 does not exist on non\\-empty\\-array\\<string, mixed\\>\\.$#"
 			count: 2
diff --git a/typo3/sysext/workspaces/Classes/Domain/Record/WorkspaceRecord.php b/typo3/sysext/workspaces/Classes/Domain/Record/WorkspaceRecord.php
index cf5be07e3d17..b31306ca83ab 100644
--- a/typo3/sysext/workspaces/Classes/Domain/Record/WorkspaceRecord.php
+++ b/typo3/sysext/workspaces/Classes/Domain/Record/WorkspaceRecord.php
@@ -78,9 +78,8 @@ class WorkspaceRecord extends AbstractRecord
         } elseif (empty($record)) {
             $record = static::fetch('sys_workspace', $uid);
         }
-        // [phpstan] Unsafe usage of new static()
-        // todo: Either mark this class or its constructor final or use new self instead.
-        return new static($record);
+
+        return GeneralUtility::makeInstance(self::class, $record);
     }
 
     /**
diff --git a/typo3/sysext/workspaces/Tests/Unit/Domain/Model/WorkspaceRecordTest.php b/typo3/sysext/workspaces/Tests/Unit/Domain/Model/WorkspaceRecordTest.php
new file mode 100644
index 000000000000..f52d8f045ac5
--- /dev/null
+++ b/typo3/sysext/workspaces/Tests/Unit/Domain/Model/WorkspaceRecordTest.php
@@ -0,0 +1,99 @@
+<?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\Workspaces\Tests\Unit\Domain\Model;
+
+use TYPO3\CMS\Core\Tests\Unit\Utility\Fixtures\GeneralUtilityFixture;
+use TYPO3\CMS\Workspaces\Domain\Record\AbstractRecord;
+use TYPO3\CMS\Workspaces\Domain\Record\WorkspaceRecord;
+use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
+
+class WorkspaceRecordTest extends UnitTestCase
+{
+    protected function setUp(): void
+    {
+        parent::setUp();
+        GeneralUtilityFixture::resetFinalClassNameCache();
+    }
+
+    protected function tearDown(): void
+    {
+        GeneralUtilityFixture::resetFinalClassNameCache();
+        parent::tearDown();
+    }
+
+    /**
+     * @test
+     */
+    public function isAbstractRecord(): void
+    {
+        $subject = new WorkspaceRecord([]);
+
+        self::assertInstanceOf(AbstractRecord::class, $subject);
+    }
+
+    /**
+     * @test
+     */
+    public function getReturnsWorkspaceRecordInstance(): void
+    {
+        $instance = WorkspaceRecord::get(1, ['title' => '']);
+
+        self::assertInstanceOf(WorkspaceRecord::class, $instance);
+    }
+
+    /**
+     * @test
+     */
+    public function getWithNonZeroUidAndNonEmptyDataReturnsInstanceWithTheProvidedData(): void
+    {
+        $title = 'some record title';
+
+        $instance = WorkspaceRecord::get(1, ['title' => $title]);
+
+        self::assertSame($title, $instance->getTitle());
+    }
+
+    /**
+     * @test
+     */
+    public function getCalledTwoTimesWithTheSameUidAndDataDataReturnsDifferentInstancesForEachCall(): void
+    {
+        $uid = 1;
+        $data = ['title' => ''];
+
+        $instance1 = WorkspaceRecord::get($uid, $data);
+        $instance2 = WorkspaceRecord::get($uid, $data);
+
+        self::assertNotSame($instance1, $instance2);
+    }
+
+    /**
+     * @test
+     */
+    public function getForConfiguredXclassReturnsInstanceOfXclass(): void
+    {
+        $xclassInstance = new class([]) extends WorkspaceRecord {
+        };
+        $xclassName = get_class($xclassInstance);
+        $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][WorkspaceRecord::class] = ['className' => $xclassName];
+
+        $instance = WorkspaceRecord::get(1, ['title' => '']);
+
+        self::assertInstanceOf($xclassName, $instance);
+    }
+}
-- 
GitLab