From 6dcc51c83229ce32bc6cce29b095bb4ecebe1963 Mon Sep 17 00:00:00 2001
From: Alexander Schnitzler <git@alexanderschnitzler.de>
Date: Sat, 25 Nov 2017 14:57:05 +0100
Subject: [PATCH] [FEATURE] Replace @cascade with @Extbase\ORM\Cascade

This patch introduces the "TYPO3\CMS\Extbase\Annotation\ORM\Cascade"
annotation that replaces the @cascade annotation which is
deprecated from now on.

Releases: master
Resolves: #83093
Change-Id: I1637d69b8bed0cdf85c009b43c3afd45ee7d29ff
Reviewed-on: https://review.typo3.org/54761
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
---
 ...ithTYPO3CMSExtbaseAnnotationORMCascade.rst | 34 +++++++++++
 ...ithTYPO3CMSExtbaseAnnotationORMCascade.rst | 59 +++++++++++++++++++
 .../Classes/Annotation/ORM/Cascade.php        | 44 ++++++++++++++
 .../Classes/Reflection/ClassSchema.php        | 13 ++++
 .../DummyClassWithAllTypesOfProperties.php    |  5 +-
 .../Reflection/ClassSchemaTest.php            | 16 +++++
 .../DummyClassWithAllTypesOfProperties.php    | 11 ++++
 .../Php/PropertyAnnotationMatcher.php         |  6 ++
 8 files changed, 186 insertions(+), 2 deletions(-)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Deprecation-83093-ReplaceCascadeWithTYPO3CMSExtbaseAnnotationORMCascade.rst
 create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Feature-83093-ReplaceCascadeWithTYPO3CMSExtbaseAnnotationORMCascade.rst
 create mode 100644 typo3/sysext/extbase/Classes/Annotation/ORM/Cascade.php

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-83093-ReplaceCascadeWithTYPO3CMSExtbaseAnnotationORMCascade.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-83093-ReplaceCascadeWithTYPO3CMSExtbaseAnnotationORMCascade.rst
new file mode 100644
index 000000000000..9bc97ec1db71
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-83093-ReplaceCascadeWithTYPO3CMSExtbaseAnnotationORMCascade.rst
@@ -0,0 +1,34 @@
+.. include:: ../../Includes.txt
+
+=====================================================================================
+Deprecation: #83093 - Replace @cascade with @TYPO3\CMS\Extbase\Annotation\ORM\Cascade
+=====================================================================================
+
+See :issue:`83093`
+
+Description
+===========
+
+The `@cascade` annotation has been deprecated and must be replaced with the doctrine annotation `@TYPO3\CMS\Extbase\Annotation\ORM\Cascade`.
+
+
+Impact
+======
+
+From version 9.0 on, `@cascade` is deprecated and will be removed in version 10.
+
+
+Affected Installations
+======================
+
+All extensions that use `@cascade`
+
+
+Migration
+=========
+
+Use `@TYPO3\CMS\Extbase\Annotation\ORM\Cascade` instead.
+
+A tyical example has been `@cascade remove` which is now `@TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove")`
+
+.. index:: PHP-API, ext:extbase, FullyScanned
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-83093-ReplaceCascadeWithTYPO3CMSExtbaseAnnotationORMCascade.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-83093-ReplaceCascadeWithTYPO3CMSExtbaseAnnotationORMCascade.rst
new file mode 100644
index 000000000000..30cfb093411a
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-83093-ReplaceCascadeWithTYPO3CMSExtbaseAnnotationORMCascade.rst
@@ -0,0 +1,59 @@
+.. include:: ../../Includes.txt
+
+=================================================================================
+Feature: #83093 - Replace @cascade with @TYPO3\CMS\Extbase\Annotation\ORM\Cascade
+=================================================================================
+
+See :issue:`83093`
+
+Description
+===========
+
+As a successor to the `@cascade` annotation, the doctrine annotation `@TYPO3\CMS\Extbase\Annotation\ORM\Cascade` has been introduced.
+
+Example:
+
+.. code-block:: php
+
+	/**
+	 * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove")
+	 */
+	public $property;
+
+Doctrine annotations are actual defined classes, therefore you can also use the annotation with a use statement.
+
+Example:
+
+.. code-block:: php
+
+	use TYPO3\CMS\Extbase\Annotation\ORM\Cascade;
+
+.. code-block:: php
+
+	/**
+	 * @Cascade("remove")
+	 */
+	public $property;
+
+Used annotations can also be aliased which the core will most likely be using a lot in the future.
+
+Example:
+
+.. code-block:: php
+
+	use TYPO3\CMS\Extbase\Annotation as Extbase;
+
+.. code-block:: php
+
+	/**
+	 * @Extbase\ORM\Cascade("remove")
+	 */
+	public $property;
+
+
+Impact
+======
+
+In 9.x there is no actual impact. Both the simple `@cascade` and `@TYPO3\CMS\Extbase\Annotation\ORM\Cascade` can be used side by side. However, `@cascade` is deprecated in 9.x and will be removed in version 10.
+
+.. index:: PHP-API, ext:extbase, FullyScanned
diff --git a/typo3/sysext/extbase/Classes/Annotation/ORM/Cascade.php b/typo3/sysext/extbase/Classes/Annotation/ORM/Cascade.php
new file mode 100644
index 000000000000..624f4012494c
--- /dev/null
+++ b/typo3/sysext/extbase/Classes/Annotation/ORM/Cascade.php
@@ -0,0 +1,44 @@
+<?php
+declare(strict_types=1);
+
+namespace TYPO3\CMS\Extbase\Annotation\ORM;
+
+/*
+ * 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!
+ */
+
+/**
+ * @Annotation
+ * @Target({"PROPERTY"})
+ */
+class Cascade
+{
+    /**
+     * @Enum({"remove"})
+     *
+     * Currently, Extbase does only support "remove".
+     *
+     * Other possible cascade operations would be: "persist", "merge", "detach", "refresh", "all"
+     * @see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html#transitive-persistence-cascade-operations
+     */
+    public $value;
+
+    /**
+     * @param array $values
+     */
+    public function __construct(array $values)
+    {
+        if (isset($values['value'])) {
+            $this->value = $values['value'];
+        }
+    }
+}
diff --git a/typo3/sysext/extbase/Classes/Reflection/ClassSchema.php b/typo3/sysext/extbase/Classes/Reflection/ClassSchema.php
index 00e488ac6a15..8082e894b7fc 100644
--- a/typo3/sysext/extbase/Classes/Reflection/ClassSchema.php
+++ b/typo3/sysext/extbase/Classes/Reflection/ClassSchema.php
@@ -18,6 +18,7 @@ use Doctrine\Common\Annotations\AnnotationReader;
 use TYPO3\CMS\Core\SingletonInterface;
 use TYPO3\CMS\Core\Utility\ClassNamingUtility;
 use TYPO3\CMS\Extbase\Annotation\Inject;
+use TYPO3\CMS\Extbase\Annotation\ORM\Cascade;
 use TYPO3\CMS\Extbase\Annotation\ORM\Lazy;
 use TYPO3\CMS\Extbase\Annotation\ORM\Transient;
 use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
@@ -246,6 +247,18 @@ class ClassSchema
                 } catch (\Exception $e) {
                 }
 
+                if ($this->properties[$propertyName]['annotations']['cascade'] !== null) {
+                    trigger_error(
+                        'Tagging properties with @cascade is deprecated and will be removed in TYPO3 v10.0.',
+                        E_USER_DEPRECATED
+                    );
+                }
+
+                if (($annotation = $annotationReader->getPropertyAnnotation($reflectionProperty, Cascade::class)) instanceof Cascade) {
+                    /** @var Cascade $annotation */
+                    $this->properties[$propertyName]['annotations']['cascade'] = $annotation->value;
+                }
+
                 try {
                     $type = TypeHandlingUtility::parseType(implode(' ', $docCommentParser->getTagValues('var')));
                 } catch (\Exception $e) {
diff --git a/typo3/sysext/extbase/Tests/Unit/Reflection/Fixture/DummyClassWithAllTypesOfProperties.php b/typo3/sysext/extbase/Tests/Unit/Reflection/Fixture/DummyClassWithAllTypesOfProperties.php
index e4fad39fd17f..459e197b17c8 100644
--- a/typo3/sysext/extbase/Tests/Unit/Reflection/Fixture/DummyClassWithAllTypesOfProperties.php
+++ b/typo3/sysext/extbase/Tests/Unit/Reflection/Fixture/DummyClassWithAllTypesOfProperties.php
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Extbase\Tests\Unit\Reflection\Fixture;
  */
 
 use TYPO3\CMS\Extbase\Annotation\Inject;
+use TYPO3\CMS\Extbase\Annotation\ORM\Cascade;
 use TYPO3\CMS\Extbase\Annotation\ORM\Transient;
 
 /**
@@ -57,12 +58,12 @@ class DummyClassWithAllTypesOfProperties
 
     /**
      * @var DummyClassWithAllTypesOfProperties
-     * @cascade remove
+     * @Cascade("remove")
      */
     public $propertyWithCascadeAnnotation;
 
     /**
-     * @cascade remove
+     * @Cascade("remove")
      */
     public $propertyWithCascadeAnnotationWithoutVarAnnotation;
 
diff --git a/typo3/sysext/extbase/Tests/UnitDeprecated/Reflection/ClassSchemaTest.php b/typo3/sysext/extbase/Tests/UnitDeprecated/Reflection/ClassSchemaTest.php
index 85bacb2b60fa..84fc91e184c8 100644
--- a/typo3/sysext/extbase/Tests/UnitDeprecated/Reflection/ClassSchemaTest.php
+++ b/typo3/sysext/extbase/Tests/UnitDeprecated/Reflection/ClassSchemaTest.php
@@ -38,4 +38,20 @@ class ClassSchemaTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
         $classSchema = new ClassSchema(Fixture\DummyClassWithLazyProperty::class);
         static::assertTrue($classSchema->getProperty('propertyWithLazyAnnotation')['annotations']['lazy']);
     }
+
+    public function testClassSchemaDetectsCascadeProperty()
+    {
+        $classSchema = new ClassSchema(Fixture\DummyClassWithAllTypesOfProperties::class);
+
+        $propertyDefinition = $classSchema->getProperty('propertyWithCascadeAnnotation');
+        static::assertSame('remove', $propertyDefinition['annotations']['cascade']);
+    }
+
+    public function testClassSchemaDetectsCascadePropertyOnlyWithVarAnnotation()
+    {
+        $classSchema = new ClassSchema(Fixture\DummyClassWithAllTypesOfProperties::class);
+
+        $propertyDefinition = $classSchema->getProperty('propertyWithCascadeAnnotationWithoutVarAnnotation');
+        static::assertNull($propertyDefinition['annotations']['cascade']);
+    }
 }
diff --git a/typo3/sysext/extbase/Tests/UnitDeprecated/Reflection/Fixture/DummyClassWithAllTypesOfProperties.php b/typo3/sysext/extbase/Tests/UnitDeprecated/Reflection/Fixture/DummyClassWithAllTypesOfProperties.php
index 1ef9b310c3ae..c6a37e7799e6 100644
--- a/typo3/sysext/extbase/Tests/UnitDeprecated/Reflection/Fixture/DummyClassWithAllTypesOfProperties.php
+++ b/typo3/sysext/extbase/Tests/UnitDeprecated/Reflection/Fixture/DummyClassWithAllTypesOfProperties.php
@@ -27,4 +27,15 @@ class DummyClassWithAllTypesOfProperties
      * @transient
      */
     public $propertyWithTransientAnnotation;
+
+    /**
+     * @var DummyClassWithAllTypesOfProperties
+     * @cascade remove
+     */
+    public $propertyWithCascadeAnnotation;
+
+    /**
+     * @cascade remove
+     */
+    public $propertyWithCascadeAnnotationWithoutVarAnnotation;
 }
diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyAnnotationMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyAnnotationMatcher.php
index 2eebc7931f58..947c2472a16d 100644
--- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyAnnotationMatcher.php
+++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyAnnotationMatcher.php
@@ -18,4 +18,10 @@ return [
             'Deprecation-83092-ReplaceTransientWithTYPO3CMSExtbaseAnnotationORMTransient.rst',
         ],
     ],
+    '@cascade' => [
+        'restFiles' => [
+            'Feature-83093-ReplaceCascadeWithTYPO3CMSExtbaseAnnotationORMCascade.rst',
+            'Deprecation-83093-ReplaceCascadeWithTYPO3CMSExtbaseAnnotationORMCascade.rst',
+        ],
+    ],
 ];
-- 
GitLab