From 5d18c6703c70b1bb3f68bd90ce4f1df7de0b7fb4 Mon Sep 17 00:00:00 2001
From: Claus Due <claus@namelesscoder.net>
Date: Sat, 12 Nov 2016 00:35:37 +0100
Subject: [PATCH] [BUGFIX] Do not serialize variables for
 TransientMemoryBackend

This change switches the internal behavior of the VariableFrontend
when combined with the TransientMemoryBackend. Before this
patch the VariableFrontend was only capable of storing strings
and would serialize all variables it received, and unserialize all
variables it retrieves.

Rather than do this unnecessary serializing, a new contract is
implemented to indicate that the backend implementing the
contract is capable of storing non-string values, including
references to objects. When the VariableFrontend detects
this contract it skips the serialize/unserialize steps.

Change-Id: I255dbda2ae3791ad6325c5b4ad67c97e172e22f4
Releases: master, 7.6
Resolves: #78664
Reviewed-on: https://review.typo3.org/50600
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Philipp Gampe <philipp.gampe@typo3.org>
Tested-by: Philipp Gampe <philipp.gampe@typo3.org>
Reviewed-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
Tested-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
---
 .../Backend/TransientBackendInterface.php     | 35 +++++++++++++++++++
 .../Cache/Backend/TransientMemoryBackend.php  |  5 +--
 .../Cache/Frontend/VariableFrontend.php       | 10 ++++--
 3 files changed, 43 insertions(+), 7 deletions(-)
 create mode 100644 typo3/sysext/core/Classes/Cache/Backend/TransientBackendInterface.php

diff --git a/typo3/sysext/core/Classes/Cache/Backend/TransientBackendInterface.php b/typo3/sysext/core/Classes/Cache/Backend/TransientBackendInterface.php
new file mode 100644
index 000000000000..720f7f23da09
--- /dev/null
+++ b/typo3/sysext/core/Classes/Cache/Backend/TransientBackendInterface.php
@@ -0,0 +1,35 @@
+<?php
+namespace TYPO3\CMS\Core\Cache\Backend;
+
+/*
+ * 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!
+ */
+
+/**
+ * A contract for a cache backends which store variables in volatile
+ * memory and as such support receiving any variable type to store.
+ *
+ * Note: respect for this contract is up to each individual frontend.
+ * The contract can be respected for a small performance boost, but
+ * the result is marginal except for cases with huge serialized
+ * data sets.
+ *
+ * Respected by the VariableFrontend which checks if the backend
+ * has this interface, in which case it allows the backend to store
+ * the value directly without serializing it to a string, and does
+ * not attempt to unserialize the string on every get() request.
+ *
+ * @api
+ */
+interface TransientBackendInterface extends BackendInterface
+{
+}
diff --git a/typo3/sysext/core/Classes/Cache/Backend/TransientMemoryBackend.php b/typo3/sysext/core/Classes/Cache/Backend/TransientMemoryBackend.php
index 32e366c59464..f80a3233323e 100644
--- a/typo3/sysext/core/Classes/Cache/Backend/TransientMemoryBackend.php
+++ b/typo3/sysext/core/Classes/Cache/Backend/TransientMemoryBackend.php
@@ -20,7 +20,7 @@ namespace TYPO3\CMS\Core\Cache\Backend;
  * This file is a backport from FLOW3
  * @api
  */
-class TransientMemoryBackend extends \TYPO3\CMS\Core\Cache\Backend\AbstractBackend implements \TYPO3\CMS\Core\Cache\Backend\TaggableBackendInterface
+class TransientMemoryBackend extends \TYPO3\CMS\Core\Cache\Backend\AbstractBackend implements TaggableBackendInterface, TransientBackendInterface
 {
     /**
      * @var array
@@ -49,9 +49,6 @@ class TransientMemoryBackend extends \TYPO3\CMS\Core\Cache\Backend\AbstractBacke
         if (!$this->cache instanceof \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface) {
             throw new \TYPO3\CMS\Core\Cache\Exception('No cache frontend has been set yet via setCache().', 1238244992);
         }
-        if (!is_string($data)) {
-            throw new \TYPO3\CMS\Core\Cache\Exception\InvalidDataException('The specified data is of type "' . gettype($data) . '" but a string is expected.', 1238244993);
-        }
         $this->entries[$entryIdentifier] = $data;
         foreach ($tags as $tag) {
             $this->tagsAndEntries[$tag][$entryIdentifier] = true;
diff --git a/typo3/sysext/core/Classes/Cache/Frontend/VariableFrontend.php b/typo3/sysext/core/Classes/Cache/Frontend/VariableFrontend.php
index e03628be9665..b79463d12afb 100644
--- a/typo3/sysext/core/Classes/Cache/Frontend/VariableFrontend.php
+++ b/typo3/sysext/core/Classes/Cache/Frontend/VariableFrontend.php
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Core\Cache\Frontend;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Cache\Backend\TransientBackendInterface;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -57,7 +58,10 @@ class VariableFrontend extends AbstractFrontend
                 GeneralUtility::callUserFunction($_funcRef, $params, $this);
             }
         }
-        $this->backend->set($entryIdentifier, serialize($variable), $tags, $lifetime);
+        if (!$this->backend instanceof TransientBackendInterface) {
+            $variable = serialize($variable);
+        }
+        $this->backend->set($entryIdentifier, $variable, $tags, $lifetime);
     }
 
     /**
@@ -81,7 +85,7 @@ class VariableFrontend extends AbstractFrontend
         if ($rawResult === false) {
             return false;
         } else {
-            return unserialize($rawResult);
+            return $this->backend instanceof TransientBackendInterface ? $rawResult : unserialize($rawResult);
         }
     }
 
@@ -104,7 +108,7 @@ class VariableFrontend extends AbstractFrontend
         foreach ($identifiers as $identifier) {
             $rawResult = $this->backend->get($identifier);
             if ($rawResult !== false) {
-                $entries[] = unserialize($rawResult);
+                $entries[] = $this->backend instanceof TransientBackendInterface ? $rawResult : unserialize($rawResult);
             }
         }
         return $entries;
-- 
GitLab