Skip to content

Commit

Permalink
Drop more usages of Serializable
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolas-grekas committed Feb 23, 2019
1 parent 2e8bf33 commit 966d44a
Show file tree
Hide file tree
Showing 27 changed files with 179 additions and 107 deletions.
6 changes: 6 additions & 0 deletions UPGRADE-4.3.md
Expand Up @@ -50,6 +50,12 @@ HttpFoundation
* The `FileinfoMimeTypeGuesser` class has been deprecated,
use `Symfony\Component\Mime\FileinfoMimeTypeGuesser` instead.

Routing
-------

* Implementing `Serializable` for `Route` and `CompiledRoute` is deprecated; if you serialize them, please
ensure your unserialization logic can recover from a failure related to an updated serialization format

Security
--------

Expand Down
6 changes: 6 additions & 0 deletions UPGRADE-5.0.md
Expand Up @@ -223,6 +223,12 @@ Process
$process = Process::fromShellCommandline('ls -l');
```

Routing
-------

* `Route` and `CompiledRoute` don't implement `Serializable` anymore; if you serialize them, please
ensure your unserialization logic can recover from a failure related to an updated serialization format

Security
--------

Expand Down
Expand Up @@ -79,15 +79,14 @@ protected function build(ContainerBuilder $container)
$container->register('logger', NullLogger::class);
}

public function serialize()
public function __sleep()
{
return serialize([$this->varDir, $this->testCase, $this->rootConfig, $this->getEnvironment(), $this->isDebug()]);
return ['varDir', 'testCase', 'rootConfig', 'environment', 'debug'];
}

public function unserialize($str)
public function __wakeup()
{
$a = unserialize($str);
$this->__construct($a[0], $a[1], $a[2], $a[3], $a[4]);
$this->__construct($this->varDir, $this->testCase, $this->rootConfig, $this->environment, $this->debug);
}

protected function getKernelParameters()
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Bundle/FrameworkBundle/composer.json
Expand Up @@ -24,7 +24,7 @@
"symfony/dependency-injection": "^4.3",
"symfony/event-dispatcher": "^4.1",
"symfony/http-foundation": "^4.3",
"symfony/http-kernel": "^4.2",
"symfony/http-kernel": "^4.3",
"symfony/polyfill-mbstring": "~1.0",
"symfony/filesystem": "~3.4|~4.0",
"symfony/finder": "~3.4|~4.0",
Expand Down
9 changes: 2 additions & 7 deletions src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
Expand Up @@ -215,14 +215,9 @@ public function testPrune()
}
}

class NotUnserializable implements \Serializable
class NotUnserializable
{
public function serialize()
{
return serialize(123);
}

public function unserialize($ser)
public function __wakeup()
{
throw new \Exception(__CLASS__);
}
Expand Down
9 changes: 2 additions & 7 deletions src/Symfony/Component/Cache/Tests/Psr16CacheTest.php
Expand Up @@ -159,14 +159,9 @@ protected function isPruned($cache, $name)
}
}

class NotUnserializable implements \Serializable
class NotUnserializable
{
public function serialize()
{
return serialize(123);
}

public function unserialize($ser)
public function __wakeup()
{
throw new \Exception(__CLASS__);
}
Expand Down
9 changes: 2 additions & 7 deletions src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php
Expand Up @@ -132,14 +132,9 @@ public function testPrune()
}
}

class NotUnserializable implements \Serializable
class NotUnserializable
{
public function serialize()
{
return serialize(123);
}

public function unserialize($ser)
public function __wakeup()
{
throw new \Exception(__CLASS__);
}
Expand Down
Expand Up @@ -24,7 +24,7 @@ var_dump([
$eHandler[0]->setExceptionHandler('print_r');

if (true) {
class Broken implements \Serializable
class Broken implements \JsonSerializable
{
}
}
Expand All @@ -37,6 +37,6 @@ array(1) {
}
object(Symfony\Component\Debug\Exception\FatalErrorException)#%d (%d) {
["message":protected]=>
string(199) "Error: Class Symfony\Component\Debug\Broken contains 2 abstract methods and must therefore be declared abstract or implement the remaining methods (Serializable::serialize, Serializable::unserialize)"
string(179) "Error: Class Symfony\Component\Debug\Broken contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (JsonSerializable::jsonSerialize)"
%a
}
1 change: 1 addition & 0 deletions src/Symfony/Component/Form/CHANGELOG.md
Expand Up @@ -15,6 +15,7 @@ CHANGELOG
* added `block_prefix` option to `BaseType`.
* added `help_html` option to display the `help` text as HTML.
* `FormError` doesn't implement `Serializable` anymore
* `FormDataCollector` has been marked as `final`
* added `label_translation_parameters`, `attr_translation_parameters`, `help_translation_parameters` options
to `FormType` to pass translation parameters to form labels, attributes (`placeholder` and `title`) and help text respectively.
The passed parameters will replace placeholders in translation messages.
Expand Down
Expand Up @@ -27,6 +27,8 @@
*
* @author Robert Schönthal <robert.schoenthal@gmail.com>
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @final since Symfony 4.3
*/
class FormDataCollector extends DataCollector implements FormDataCollectorInterface
{
Expand Down Expand Up @@ -229,15 +231,20 @@ public function getData()
return $this->data;
}

public function serialize()
/**
* @internal
*/
public function __sleep()
{
foreach ($this->data['forms_by_hash'] as &$form) {
if (isset($form['type_class']) && !$form['type_class'] instanceof ClassStub) {
$form['type_class'] = new ClassStub($form['type_class']);
}
}

return serialize($this->cloneVar($this->data));
$this->data = $this->cloneVar($this->data);

return parent::__sleep();
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Component/Form/composer.json
Expand Up @@ -31,7 +31,7 @@
"symfony/config": "~3.4|~4.0",
"symfony/console": "~3.4|~4.0",
"symfony/http-foundation": "~3.4|~4.0",
"symfony/http-kernel": "~3.4|~4.0",
"symfony/http-kernel": "~4.3",
"symfony/security-csrf": "~3.4|~4.0",
"symfony/translation": "~4.2",
"symfony/var-dumper": "~3.4|~4.0"
Expand All @@ -41,7 +41,7 @@
"symfony/dependency-injection": "<3.4",
"symfony/doctrine-bridge": "<3.4",
"symfony/framework-bundle": "<3.4",
"symfony/http-kernel": "<3.4",
"symfony/http-kernel": "<4.3",
"symfony/translation": "<4.2",
"symfony/twig-bridge": "<3.4.5|<4.0.5,>=4.0"
},
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/HttpKernel/CHANGELOG.md
Expand Up @@ -4,9 +4,14 @@ CHANGELOG
4.3.0
-----

* `KernelInterface` doesn't extend `Serializable` anymore
* deprecated the `Kernel::serialize()` and `unserialize()` methods
* increased the priority of `Symfony\Component\HttpKernel\EventListener\AddRequestFormatsListener`
* made `Symfony\Component\HttpKernel\EventListenerLocaleListener` set the default locale early
* made `FileLinkFormatter` final and not implement `Serializable` anymore
* the base `DataCollector` doesn't implement `Serializable` anymore, you should
store all the serialized state in the data property instead
* `DumpDataCollector` has been marked as `final`

4.2.0
-----
Expand Down
30 changes: 29 additions & 1 deletion src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php
Expand Up @@ -26,7 +26,7 @@
* @author Fabien Potencier <fabien@symfony.com>
* @author Bernhard Schussek <bschussek@symfony.com>
*/
abstract class DataCollector implements DataCollectorInterface, \Serializable
abstract class DataCollector implements DataCollectorInterface
{
protected $data = [];

Expand All @@ -35,16 +35,26 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable
*/
private $cloner;

/**
* @deprecated since Symfony 4.3, store all the serialized state in the data property instead
*/
public function serialize()
{
@trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3, store all the serialized state in the data property instead.', __METHOD__), E_USER_DEPRECATED);

$trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
$isCalledFromOverridingMethod = isset($trace[1]['function'], $trace[1]['object']) && 'serialize' === $trace[1]['function'] && $this === $trace[1]['object'];

return $isCalledFromOverridingMethod ? $this->data : serialize($this->data);
}

/**
* @deprecated since Symfony 4.3, store all the serialized state in the data property instead
*/
public function unserialize($data)
{
@trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3, store all the serialized state in the data property instead.', __METHOD__), E_USER_DEPRECATED);

$this->data = \is_array($data) ? $data : unserialize($data);
}

Expand Down Expand Up @@ -100,4 +110,22 @@ protected function getCasters()

return $casters;
}

public function __sleep()
{
if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'serialize'))->getDeclaringClass()->name) {
@trigger_error(sprintf('Implementing the "%s::serialize()" method is deprecated since Symfony 4.3, store all the serialized state in the "data" property instead.', $c), E_USER_DEPRECATED);
$this->data = $this->serialize();
}

return ['data'];
}

public function __wakeup()
{
if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'unserialize'))->getDeclaringClass()->name) {
@trigger_error(sprintf('Implementing the "%s::unserialize()" method is deprecated since Symfony 4.3, store all the serialized state in the "data" property instead.', $c), E_USER_DEPRECATED);
$this->unserialize($this->data);
}
}
}
Expand Up @@ -25,6 +25,8 @@

/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.3
*/
class DumpDataCollector extends DataCollector implements DataDumperInterface
{
Expand Down Expand Up @@ -85,6 +87,9 @@ public function dump(Data $data)
$this->isCollected = false;
}

if (!$this->dataCount) {
$this->data = [];
}
$this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt');
++$this->dataCount;

Expand All @@ -95,6 +100,10 @@ public function dump(Data $data)

public function collect(Request $request, Response $response, \Exception $exception = null)
{
if (!$this->dataCount) {
$this->data = [];
}

// Sub-requests and programmatic calls stay in the collected profile.
if ($this->dumper || ($this->requestStack && $this->requestStack->getMasterRequest() !== $request) || $request->isXmlHttpRequest() || $request->headers->has('Origin')) {
return;
Expand Down Expand Up @@ -136,28 +145,38 @@ public function reset()
$this->clonesIndex = 0;
}

public function serialize()
/**
* @internal
*/
public function __sleep()
{
if (!$this->dataCount) {
$this->data = [];
}

if ($this->clonesCount !== $this->clonesIndex) {
return 'a:0:{}';
return [];
}

$this->data[] = $this->fileLinkFormat;
$this->data[] = $this->charset;
$ser = serialize($this->data);
$this->data = [];
$this->dataCount = 0;
$this->isCollected = true;

return $ser;
return parent::__sleep();
}

public function unserialize($data)
/**
* @internal
*/
public function __wakeup()
{
$this->data = unserialize($data);
parent::__wakeup();

$charset = array_pop($this->data);
$fileLinkFormat = array_pop($this->data);
$this->dataCount = \count($this->data);

self::__construct($this->stopwatch, $fileLinkFormat, $charset);
}

Expand All @@ -178,6 +197,10 @@ public function getDumps($format, $maxDepthLimit = -1, $maxItemsPerDepth = -1)
}
$dumps = [];

if (!$this->dataCount) {
return $this->data = [];
}

foreach ($this->data as $dump) {
$dumper->dump($dump['data']->withMaxDepth($maxDepthLimit)->withMaxItemsPerDepth($maxItemsPerDepth));
$dump['data'] = stream_get_contents($data, -1, 0);
Expand All @@ -196,7 +219,7 @@ public function getName()

public function __destruct()
{
if (0 === $this->clonesCount-- && !$this->isCollected && $this->data) {
if (0 === $this->clonesCount-- && !$this->isCollected && $this->dataCount) {
$this->clonesCount = 0;
$this->isCollected = true;

Expand Down
9 changes: 9 additions & 0 deletions src/Symfony/Component/HttpKernel/Kernel.php
Expand Up @@ -833,13 +833,22 @@ public static function stripComments($source)
return $output;
}

/**
* @deprecated since Symfony 4.3
*/
public function serialize()
{
@trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3.', __METHOD__), E_USER_DEPRECATED);

return serialize([$this->environment, $this->debug]);
}

/**
* @deprecated since Symfony 4.3
*/
public function unserialize($data)
{
@trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3.', __METHOD__), E_USER_DEPRECATED);
list($environment, $debug) = unserialize($data, ['allowed_classes' => false]);

$this->__construct($environment, $debug);
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Component/HttpKernel/KernelInterface.php
Expand Up @@ -24,7 +24,7 @@
*
* @method string getProjectDir() Gets the project dir (path of the project's composer file) - not defining it is deprecated since Symfony 4.2
*/
interface KernelInterface extends HttpKernelInterface, \Serializable
interface KernelInterface extends HttpKernelInterface
{
/**
* Returns an array of bundles to register.
Expand Down

0 comments on commit 966d44a

Please sign in to comment.