Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
66.67% covered (warning)
66.67%
2 / 3
CRAP
81.48% covered (warning)
81.48%
22 / 27
TagAwareMarshaller
0.00% covered (danger)
0.00%
0 / 1
66.67% covered (warning)
66.67%
2 / 3
21.29
81.48% covered (warning)
81.48%
22 / 27
 __construct
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 marshall
0.00% covered (danger)
0.00%
0 / 1
14.69
68.75% covered (warning)
68.75%
11 / 16
 unmarshall
100.00% covered (success)
100.00%
1 / 1
7
100.00% covered (success)
100.00%
9 / 9
<?php
/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace Symfony\Component\Cache\Marshaller;
/**
 * A marshaller optimized for data structures generated by AbstractTagAwareAdapter.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 */
class TagAwareMarshaller implements MarshallerInterface
{
    private $marshaller;
    public function __construct(MarshallerInterface $marshaller = null)
    {
        $this->marshaller = $marshaller ?? new DefaultMarshaller();
    }
    /**
     * {@inheritdoc}
     */
    public function marshall(array $values, ?array &$failed): array
    {
        $failed = $notSerialized = $serialized = [];
        foreach ($values as $id => $value) {
            if (\is_array($value) && \is_array($value['tags'] ?? null) && \array_key_exists('value', $value) && \count($value) === 2 + (\is_string($value['meta'] ?? null) && 8 === \strlen($value['meta']))) {
                // if the value is an array with keys "tags", "value" and "meta", use a compact serialization format
                // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F allow detecting this format quickly in unmarshall()
                $v = $this->marshaller->marshall($value, $f);
                if ($f) {
                    $f = [];
                    $failed[] = $id;
                } else {
                    if ([] === $value['tags']) {
                        $v['tags'] = '';
                    }
                    $serialized[$id] = "\x9D".($value['meta'] ?? "\0\0\0\0\0\0\0\0").pack('N', \strlen($v['tags'])).$v['tags'].$v['value'];
                    $serialized[$id][9] = "\x5F";
                }
            } else {
                // other arbitratry values are serialized using the decorated marshaller below
                $notSerialized[$id] = $value;
            }
        }
        if ($notSerialized) {
            $serialized += $this->marshaller->marshall($notSerialized, $f);
            $failed = array_merge($failed, $f);
        }
        return $serialized;
    }
    /**
     * {@inheritdoc}
     */
    public function unmarshall(string $value)
    {
        // detect the compact format used in marshall() using magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
        if (13 >= \strlen($value) || "\x9D" !== $value[0] || "\0" !== $value[5] || "\x5F" !== $value[9]) {
            return $this->marshaller->unmarshall($value);
        }
        // data consists of value, tags and metadata which we need to unpack
        $meta = substr($value, 1, 12);
        $meta[8] = "\0";
        $tagLen = unpack('Nlen', $meta, 8)['len'];
        $meta = substr($meta, 0, 8);
        return [
            'value' => $this->marshaller->unmarshall(substr($value, 13 + $tagLen)),
            'tags' => $tagLen ? $this->marshaller->unmarshall(substr($value, 13, $tagLen)) : [],
            'meta' => "\0\0\0\0\0\0\0\0" === $meta ? null : $meta,
        ];
    }
}