Completed
Push — develop ( e55011...fb44ee )
by
unknown
13s
created

HashHandler   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 144
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 36.36%

Importance

Changes 0
Metric Value
wmc 15
c 0
b 0
f 0
lcom 1
cbo 5
dl 0
loc 144
ccs 16
cts 44
cp 0.3636
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A serializeHashToJson() 0 8 1
B deserializeHashFromJson() 0 32 6
A getCurrentRequestContent() 0 8 2
A isSequentialArrayCase() 0 8 3
A getLocationCounter() 0 10 2
1
<?php
2
/**
3
 * HashHandler class file
4
 */
5
6
namespace Graviton\DocumentBundle\Serializer\Handler;
7
8
use JMS\Serializer\Context;
9
use JMS\Serializer\JsonDeserializationVisitor;
10
use JMS\Serializer\JsonSerializationVisitor;
11
use Graviton\DocumentBundle\Entity\Hash;
12
use Symfony\Component\HttpFoundation\RequestStack;
13
14
/**
15
 * Hash handler for JMS serializer
16
 *
17
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
18
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
19
 * @link     http://swisscom.ch
20
 */
21
class HashHandler
22
{
23
24
    /**
25
     * @var RequestStack
26
     */
27
    private $requestStack;
28
29
    /**
30
     * @var array
31
     */
32
    private $seenCounter = [];
33
34
    /**
35
     * @var null|object
36
     */
37
    private $currentRequestContent = null;
38
39
    /**
40
     * HashHandler constructor.
41
     *
42
     * @param RequestStack $requestStack request stack
43
     */
44 4
    public function __construct(RequestStack $requestStack)
45
    {
46 4
        $this->requestStack = $requestStack;
47 4
    }
48
49
    /**
50
     * Serialize Hash object
51
     *
52
     * @param JsonSerializationVisitor $visitor Visitor
53
     * @param Hash                     $data    Data
54
     * @param array                    $type    Type
55
     * @param Context                  $context Context
56
     * @return Hash
57
     */
58 2
    public function serializeHashToJson(
59
        JsonSerializationVisitor $visitor,
60
        Hash $data,
61
        array $type,
62
        Context $context
63
    ) {
64 2
        return new Hash($data);
65
    }
66
67
    /**
68
     * Deserialize Hash object
69
     *
70
     * @param JsonDeserializationVisitor $visitor Visitor
71
     * @param array                      $data    Data
72
     * @param array                      $type    Type
73
     * @param Context                    $context Context
74
     * @return Hash
75
     */
76 2
    public function deserializeHashFromJson(
77
        JsonDeserializationVisitor $visitor,
78
        array $data,
79
        array $type,
80
        Context $context
81
    ) {
82 2
        $currentPath = $context->getCurrentPath();
83 2
        $currentRequestContent = $this->getCurrentRequestContent();
84 2
        $dataObj = null;
85
86 2
        if (!is_null($currentRequestContent)) {
87
            $dataObj = $currentRequestContent;
88
            foreach ($currentPath as $pathElement) {
89
                if (isset($dataObj->{$pathElement})) {
90
                    $dataObj = $dataObj->{$pathElement};
91
                } else {
92
                    $dataObj = null;
93
                    break;
94
                }
95
            }
96
        }
97
98 2
        if (!is_null($dataObj)) {
99
            if ($this->isSequentialArrayCase($dataObj, $data)) {
100
                $dataObj = $dataObj[$this->getLocationCounter($currentPath)];
101
            }
102
103
            $data = $dataObj;
104
        }
105
106 2
        return new Hash($visitor->visitArray((array) $data, $type, $context));
107
    }
108
109
    /**
110
     * returns the json_decoded content of the current request. if there is no request, it
111
     * will return null
112
     *
113
     * @return mixed|null|object the json_decoded request content
114
     */
115 2
    private function getCurrentRequestContent()
116
    {
117 2
        $currentRequest = $this->requestStack->getCurrentRequest();
118 2
        if (!is_null($currentRequest)) {
119
            $this->currentRequestContent = json_decode($currentRequest->getContent());
120
        }
121 2
        return $this->currentRequestContent;
122
    }
123
124
    /**
125
     * this checks for a special case which this new approach is really flawed. if this
126
     * handler is used to deserialize an array, we are not aware of the current index in the iteration.
127
     * so we record for what we have been called how many times ($this->seenCounter) and
128
     * if this function here returns true, we only return the index specified by the seencounter.
129
     *
130
     * we assume that we are in this special case when the userData (the one parsed from the request)
131
     * has sequential keys *and* they are different from the keys that the serializer data gives us.
132
     *
133
     * @param array $userArr       data from users request
134
     * @param array $serializerArr data from the serializer
135
     *
136
     * @return bool true if yes, false otherwise
137
     */
138
    private function isSequentialArrayCase($userArr, $serializerArr)
139
    {
140
        return (
141
            is_array($userArr) &&
142
            (array_keys($userArr) == range(0, count($userArr) - 1)) &&
143
            array_keys($userArr) != array_keys($serializerArr)
144
        );
145
    }
146
147
    /**
148
     * convenience function for the location counting for the "sequential array case" as described above.
149
     *
150
     * @param array $location the current path from the serializer
151
     *
152
     * @return int the counter
153
     */
154
    private function getLocationCounter($location)
155
    {
156
        $locationHash = md5(implode(',', $location));
157
        if (!isset($this->seenCounter[$locationHash])) {
158
            $this->seenCounter[$locationHash] = 0;
159
        } else {
160
            $this->seenCounter[$locationHash]++;
161
        }
162
        return $this->seenCounter[$locationHash];
163
    }
164
}
165