Completed
Push — master ( de2382...5d49dc )
by Lucas
15:10
created

HashType::processDynExtRefs()   C

Complexity

Conditions 11
Paths 4

Size

Total Lines 35
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 18.3389
Metric Value
dl 0
loc 35
ccs 17
cts 28
cp 0.6071
rs 5.2653
cc 11
eloc 23
nc 4
nop 1
crap 18.3389

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * HashType class file
4
 */
5
6
namespace Graviton\DocumentBundle\Types;
7
8
use Doctrine\ODM\MongoDB\Types\Type;
9
use Graviton\DocumentBundle\Entity\ExtReference;
10
use Graviton\DocumentBundle\Entity\Hash;
11
use Graviton\DocumentBundle\Service\ExtReferenceConverterInterface;
12
13
/**
14
 * Hash type
15
 *
16
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
17
 * @license  http://opensource.org/licenses/MIT MIT License
18
 * @link     http://swisscom.ch
19
 */
20
class HashType extends Type
21
{
22
23
    /**
24
     * extref converter
25
     *
26
     * @var ExtReferenceConverterInterface
27
     */
28
    private static $extRefConverter;
29
30
    /**
31
     * sets the converter
32
     *
33
     * @param ExtReferenceConverterInterface $converter converter
34
     *
35
     * @return void
36
     */
37 2
    public function setExtRefConverter(ExtReferenceConverterInterface $converter)
38
    {
39 2
        self::$extRefConverter = $converter;
40 2
    }
41
42
    /**
43
     * Convert DB value to PHP representation
44
     *
45
     * @param mixed $value Value to convert
46
     * @return Hash|null
47
     */
48 8
    public static function convertToPhp($value)
49
    {
50 8
        return is_array($value) ? new Hash(self::processDynExtRefs($value)) : null;
51
    }
52
53
    /**
54
     * Convert PHP value to MongoDb representation
55
     *
56
     * @param mixed $value Value to convert
57
     * @return object|null
58
     */
59 8
    public static function convertToDb($value)
60
    {
61 8
        $dbValue = null;
62
63 8
        if (is_array($value)) {
64 4
            $dbValue = (object) $value;
65 4
        } elseif ($value instanceof \ArrayObject) {
66 8
            $dbValue = (object) $value->getArrayCopy();
67 6
        } elseif (is_object($value)) {
68
            $dbValue = (object) get_object_vars($value);
69
        }
70
71 8
        if (!is_null($dbValue)) {
72 8
            $dbValue = (object) self::processDynExtRefs($dbValue);
73 4
        }
74
75 8
        return $dbValue;
76
    }
77
78
    /**
79
     * loops our structure recursively to find all $ref objects that need to be converted
80
     * either from that or to that..
81
     *
82
     * @param mixed $input input structure
83
     *
84
     * @return array altered structure with replaced $ref objects
85
     */
86 16
    public static function processDynExtRefs($input)
87
    {
88 16
        if ($input instanceof \stdClass) {
89 8
            if (!empty(get_object_vars($input))) {
90 8
                $input = self::processDynExtRefs(get_object_vars($input));
91 4
            }
92 8
            return $input;
93
        }
94
95 16
        $externalRefFieldName = '$ref';
96 16
        $internalRefFieldName = 'ref';
97
98 16
        if (is_array($input)) {
99 16
            foreach ($input as $key => $value) {
100 16
                if ($key === $internalRefFieldName) {
101
                    if (is_array($value) && isset($value['$ref']) && isset($value['$id'])) {
102
                        $extRef = ExtReference::create($value['$ref'], $value['$id']);
103
                        $input[$externalRefFieldName] = self::$extRefConverter->getUrl($extRef);
104
                        unset($input[$internalRefFieldName]);
105
                    }
106 16
                } elseif ($key === $externalRefFieldName) {
107
                    $extRef = self::$extRefConverter->getExtReference($value);
108
                    $input[$internalRefFieldName] = $extRef->jsonSerialize();
109
                    unset($input[$externalRefFieldName]);
110
                } else {
111 16
                    if (is_array($value)) {
112
                        $value = self::processDynExtRefs($value);
113
                    }
114 16
                    $input[$key] = $value;
115
                }
116 8
            }
117 8
        }
118
119 16
        return $input;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $input; (object|integer|double|string|null|boolean|array) is incompatible with the return type documented by Graviton\DocumentBundle\...Type::processDynExtRefs of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
120
    }
121
122
    /**
123
     * Convert to PHP value
124
     *
125
     * @param mixed $value Db value
126
     * @return Hash|null
127
     */
128 2
    public function convertToPHPValue($value)
129
    {
130 2
        return static::convertToPhp($value);
131
    }
132
133
    /**
134
     * Closure to convert to PHP value
135
     *
136
     * @return string
137
     */
138 4
    public function closureToPHP()
139
    {
140 4
        return '$return = \\'.static::class.'::convertToPhp($value);';
141
    }
142
143
    /**
144
     * Convert to DB value
145
     *
146
     * @param mixed $value PHP value
147
     * @return object|null
148
     */
149 2
    public function convertToDatabaseValue($value)
150
    {
151 2
        return static::convertToDb($value);
152
    }
153
154
    /**
155
     * Closure to convert to DB value
156
     *
157
     * @return string
158
     */
159 2
    public function closureToMongo()
160
    {
161 2
        return '$return = \\'.static::class.'::convertToDb($value);';
162
    }
163
}
164