Browse Source

Fixes #15410: Added serialization abstraction layer under `yii\serialize\*` namespace

tags/3.0.0-alpha1
Alexander Makarov 7 years ago committed by GitHub
parent
commit
87fde26d6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      framework/CHANGELOG.md
  2. 3
      framework/UPGRADE.md
  3. 53
      framework/caching/SimpleCache.php
  4. 45
      framework/serialize/CallbackSerializer.php
  5. 36
      framework/serialize/IgbinarySerializer.php
  6. 44
      framework/serialize/JsonSerializer.php
  7. 35
      framework/serialize/PhpSerializer.php
  8. 31
      framework/serialize/SerializerInterface.php
  9. 27
      tests/framework/serialize/CallbackSerializerTest.php
  10. 37
      tests/framework/serialize/IgbinarySerializerTest.php
  11. 24
      tests/framework/serialize/JsonSerializerTest.php
  12. 24
      tests/framework/serialize/PhpSerializerTest.php
  13. 51
      tests/framework/serialize/SerializerTest.php

1
framework/CHANGELOG.md

@ -19,6 +19,7 @@ Yii Framework 2 Change Log
- Enh #12592: Optimized `yii\filters\AccessController` on processing accessrules (dynasource)
- Enh #12938: Allow to pass additional parameters to `yii\base\View::renderDynamic()` (mikehaertl)
- Enh #13006: Added a `/` to the `yii\captcha\Captcha::$captchaAction` string to work correctly in a module also (boehsermoe)
- Enh #15410: Added serialization abstraction layer under `yii\serialize\*` namespace (klimov-paul)
- Removed methods marked as deprecated in 2.0.x (samdark)
- Chg #14784: Signature of `yii\web\RequestParserInterface::parse()` changed to accept `yii\web\Request` instance as a sole argument (klimov-paul)
- Chg #10771: Consistent behavior of `run()` method in all framework widgets. All return the result now for better extensibility (pkirill99, cebe)

3
framework/UPGRADE.md

@ -106,6 +106,9 @@ Upgrade from Yii 2.0.x
be configured there. Creating your own cache implementation you should implement `\Psr\SimpleCache\CacheInterface` or
extend `yii\caching\SimpleCache` abstract class. Use `yii\caching\CacheInterface` only if you wish to replace `yii\caching\Cache`
component providing your own solution for cache dependency handling.
* `yii\caching\SimpleCache::$serializer` now should be `yii\serialize\SerializerInterface` instance or its DI compatible configuration.
Thus it does no longer accept pair of serialize/unserialize functions as an array. Use `yii\serialize\CallbackSerializer` or
other predefined serializer class from `yii\serialize\*` namespace instead.
* Console command used to clear cache now calls related actions "clear" instead of "flush".
* Yii autoloader was removed in favor of Composer-generated one. You should remove explicit inclusion of `Yii.php` from
your entry `index.php` scripts. In case you have relied on class map, use `composer.json` instead of configuring it

53
framework/caching/SimpleCache.php

@ -9,7 +9,10 @@ namespace yii\caching;
use Psr\SimpleCache\CacheInterface;
use yii\base\Component;
use yii\di\Instance;
use yii\helpers\StringHelper;
use yii\serialize\PhpSerializer;
use yii\serialize\SerializerInterface;
/**
* SimpleCache is the base class for cache classes implementing pure PSR-16 [[CacheInterface]].
@ -46,32 +49,49 @@ abstract class SimpleCache extends Component implements CacheInterface
*/
public $keyPrefix = '';
/**
* @var null|array|false the functions used to serialize and unserialize cached data. Defaults to null, meaning
* using the default PHP `serialize()` and `unserialize()` functions. If you want to use some more efficient
* serializer (e.g. [igbinary](http://pecl.php.net/package/igbinary)), you may configure this property with
* a two-element array. The first element specifies the serialization function, and the second the deserialization
* function. If this property is set false, data will be directly sent to and retrieved from the underlying
* @var SerializerInterface|array|false the serializer to be used for serializing and unserializing of the cached data.
* Serializer should be an instance of [[SerializerInterface]] or its DI compatible configuration. For example:
*
* ```php
* [
* 'class' => \yii\serialize\IgbinarySerializer::class
* ]
* ```
*
* Default is [[PhpSerializer]], meaning using the default PHP `serialize()` and `unserialize()` functions.
*
* If this property is set `false`, data will be directly sent to and retrieved from the underlying
* cache component without any serialization or deserialization. You should not turn off serialization if
* you are using [[Dependency|cache dependency]], because it relies on data serialization. Also, some
* implementations of the cache can not correctly save and retrieve data different from a string type.
*/
public $serializer;
public $serializer = PhpSerializer::class;
/**
* {@inheritdoc}
*/
public function init()
{
parent::init();
if ($this->serializer !== false) {
$this->serializer = Instance::ensure($this->serializer instanceof \Closure ? call_user_func($this->serializer) : $this->serializer, SerializerInterface::class);
}
}
/**
* {@inheritdoc}
*/
public function get($key, $default = null)
{
$key = $this->normalizeKey($key);
$value = $this->getValue($key);
if ($value === false || $this->serializer === false) {
return $default;
} elseif ($this->serializer === null) {
return unserialize($value);
}
return call_user_func($this->serializer[1], $value);
return $this->serializer->unserialize($value);
}
/**
@ -91,8 +111,7 @@ abstract class SimpleCache extends Component implements CacheInterface
if ($this->serializer === false) {
$results[$key] = $values[$newKey];
} else {
$results[$key] = $this->serializer === null ? unserialize($values[$newKey])
: call_user_func($this->serializer[1], $values[$newKey]);
$results[$key] = $this->serializer->unserialize($values[$newKey]);
}
}
}
@ -114,10 +133,8 @@ abstract class SimpleCache extends Component implements CacheInterface
*/
public function set($key, $value, $ttl = null)
{
if ($this->serializer === null) {
$value = serialize($value);
} elseif ($this->serializer !== false) {
$value = call_user_func($this->serializer[0], $value);
if ($this->serializer !== false) {
$value = $this->serializer->serialize($value);
}
$key = $this->normalizeKey($key);
$ttl = $this->normalizeTtl($ttl);
@ -131,10 +148,8 @@ abstract class SimpleCache extends Component implements CacheInterface
{
$data = [];
foreach ($values as $key => $value) {
if ($this->serializer === null) {
$value = serialize($value);
} elseif ($this->serializer !== false) {
$value = call_user_func($this->serializer[0], $value);
if ($this->serializer !== false) {
$value = $this->serializer->serialize($value);
}
$key = $this->normalizeKey($key);
$data[$key] = $value;

45
framework/serialize/CallbackSerializer.php

@ -0,0 +1,45 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\serialize;
use yii\base\BaseObject;
/**
* CallbackSerializer serializes data via custom PHP callback.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.1.0
*/
class CallbackSerializer extends BaseObject implements SerializerInterface
{
/**
* @var callable PHP callback, which should be used to serialize value.
*/
public $serialize;
/**
* @var callable PHP callback, which should be used to unserialize value.
*/
public $unserialize;
/**
* {@inheritdoc}
*/
public function serialize($value)
{
return call_user_func($this->serialize, $value);
}
/**
* {@inheritdoc}
*/
public function unserialize($value)
{
return call_user_func($this->unserialize, $value);
}
}

36
framework/serialize/IgbinarySerializer.php

@ -0,0 +1,36 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\serialize;
use yii\base\BaseObject;
/**
* IgbinarySerializer uses [Igbinary PHP extension](http://pecl.php.net/package/igbinary) for serialization.
* Make sure you have 'igbinary' PHP extension install at your system before attempt to use this serializer.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.1.0
*/
class IgbinarySerializer extends BaseObject implements SerializerInterface
{
/**
* {@inheritdoc}
*/
public function serialize($value)
{
return igbinary_serialize($value);
}
/**
* {@inheritdoc}
*/
public function unserialize($value)
{
return igbinary_unserialize($value);
}
}

44
framework/serialize/JsonSerializer.php

@ -0,0 +1,44 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\serialize;
use yii\base\BaseObject;
use yii\helpers\Json;
/**
* JsonSerializer serializes data in JSON format.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.1.0
*/
class JsonSerializer extends BaseObject implements SerializerInterface
{
/**
* @var integer the encoding options. For more details please refer to
* <http://www.php.net/manual/en/function.json-encode.php>.
* Default is `JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE`.
*/
public $options = 320;
/**
* {@inheritdoc}
*/
public function serialize($value)
{
return Json::encode($value, $this->options);
}
/**
* {@inheritdoc}
*/
public function unserialize($value)
{
return Json::decode($value);
}
}

35
framework/serialize/PhpSerializer.php

@ -0,0 +1,35 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\serialize;
use yii\base\BaseObject;
/**
* PhpSerializer uses native PHP `serialize()` and `unserialize()` functions for the serialization.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.1.0
*/
class PhpSerializer extends BaseObject implements SerializerInterface
{
/**
* {@inheritdoc}
*/
public function serialize($value)
{
return serialize($value);
}
/**
* {@inheritdoc}
*/
public function unserialize($value)
{
return unserialize($value);
}
}

31
framework/serialize/SerializerInterface.php

@ -0,0 +1,31 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\serialize;
/**
* SerializerInterface defines serializer interface.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.1.0
*/
interface SerializerInterface
{
/**
* Serializes given value.
* @param mixed $value value to be serialized
* @return string serialized value.
*/
public function serialize($value);
/**
* Restores value from its serialized representations
* @param string $value serialized string.
* @return mixed restored value
*/
public function unserialize($value);
}

27
tests/framework/serialize/CallbackSerializerTest.php

@ -0,0 +1,27 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\serialize;
use yii\serialize\CallbackSerializer;
/**
* @group serialize
*/
class CallbackSerializerTest extends SerializerTest
{
/**
* {@inheritdoc}
*/
protected function createSerializer()
{
return new CallbackSerializer([
'serialize' => 'serialize',
'unserialize' => 'unserialize',
]);
}
}

37
tests/framework/serialize/IgbinarySerializerTest.php

@ -0,0 +1,37 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\serialize;
use yii\serialize\IgbinarySerializer;
/**
* @group serialize
*/
class IgbinarySerializerTest extends SerializerTest
{
/**
* {@inheritdoc}
*/
protected function setUp()
{
if (!function_exists('igbinary_serialize')) {
$this->markTestSkipped('igbinary extension is required.');
return;
}
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function createSerializer()
{
return new IgbinarySerializer();
}
}

24
tests/framework/serialize/JsonSerializerTest.php

@ -0,0 +1,24 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\serialize;
use yii\serialize\JsonSerializer;
/**
* @group serialize
*/
class JsonSerializerTest extends SerializerTest
{
/**
* {@inheritdoc}
*/
protected function createSerializer()
{
return new JsonSerializer();
}
}

24
tests/framework/serialize/PhpSerializerTest.php

@ -0,0 +1,24 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\serialize;
use yii\serialize\PhpSerializer;
/**
* @group serialize
*/
class PhpSerializerTest extends SerializerTest
{
/**
* {@inheritdoc}
*/
protected function createSerializer()
{
return new PhpSerializer();
}
}

51
tests/framework/serialize/SerializerTest.php

@ -0,0 +1,51 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\serialize;
use yiiunit\TestCase;
/**
* @group serialize
*/
abstract class SerializerTest extends TestCase
{
/**
* Creates serializer instance for the tests.
* @return \yii\serialize\SerializerInterface
*/
abstract protected function createSerializer();
/**
* Data provider for [[testSerialize()]]
* @return array test data.
*/
public function dataProviderSerialize()
{
return [
['some-string'],
[345],
[56.89],
[['some' => 'array']],
];
}
/**
* @dataProvider dataProviderSerialize
*
* @param mixed $value
*/
public function testSerialize($value)
{
$serializer = $this->createSerializer();
$serialized = $serializer->serialize($value);
$this->assertTrue(is_string($serialized));
$this->assertEquals($value, $serializer->unserialize($serialized));
}
}
Loading…
Cancel
Save