OrderByLeafNode::buildComparisonFunction()   C
last analyzed

Complexity

Conditions 17
Paths 3

Size

Total Lines 58
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 17
eloc 42
nc 3
nop 1
dl 0
loc 58
rs 5.2166
c 0
b 0
f 0

How to fix   Long Method    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
declare(strict_types=1);
4
5
namespace POData\UriProcessor\QueryProcessor\OrderByParser;
6
7
use Closure;
8
use InvalidArgumentException;
9
use POData\Common\Messages;
10
use POData\Providers\Metadata\ResourceProperty;
11
use POData\Providers\Metadata\ResourceType;
12
use POData\Providers\Metadata\Type\DateTime;
13
use POData\Providers\Metadata\Type\Guid;
14
use POData\Providers\Metadata\Type\StringType;
15
16
/**
17
 * Class OrderByLeafNode.
18
 *
19
 * Type to represent leaf node of 'OrderBy Tree', a leaf node
20
 * in OrderByTree represents last sub path segment of an orderby
21
 * path segment.
22
 */
23
class OrderByLeafNode extends OrderByBaseNode
24
{
25
    /**
26
     * The order of sorting to be performed using this property.
27
     *
28
     * @var bool
29
     */
30
    private $isAscending;
31
32
    private $anonymousFunction;
33
34
    /**
35
     * Constructs new instance of OrderByLeafNode.
36
     *
37
     * @param string           $propertyName     Name of the property
38
     *                                           corresponds to the
39
     *                                           sub path segment represented
40
     *                                           by this node
41
     * @param ResourceProperty $resourceProperty Resource property corresponds
42
     *                                           to the sub path
43
     *                                           segment represented by this node
44
     * @param bool             $isAscending      The order of sorting to be
45
     *                                           performed, true for
46
     *                                           ascending order and false
47
     *                                           for descending order
48
     */
49
    public function __construct(
50
        $propertyName,
51
        ResourceProperty $resourceProperty,
52
        $isAscending
53
    ) {
54
        parent::__construct($propertyName, $resourceProperty);
55
        $this->isAscending = $isAscending;
56
    }
57
58
    /**
59
     * (non-PHPdoc).
60
     *
61
     * @see library/POData/QueryProcessorOrderByParser.OrderByBaseNode::free()
62
     */
63
    public function free(): void
64
    {
65
        // By the time we call this function, the top level sorter function
66
        // will be already generated so we can free
67
        unset($this->anonymousFunction);
68
        $this->anonymousFunction = null;
69
    }
70
71
    /**
72
     * (non-PHPdoc).
73
     *
74
     * @return ResourceType
75
     * @see library/POData/QueryProcessorOrderByParser.OrderByBaseNode::getResourceType()
76
     */
77
    public function getResourceType(): ResourceType
78
    {
79
        return $this->resourceProperty->getResourceType();
80
    }
81
82
    /**
83
     * To check the order of sorting to be performed.
84
     *
85
     * @return bool
86
     */
87
    public function isAscending(): bool
88
    {
89
        return $this->isAscending;
90
    }
91
92
    /**
93
     * Build comparison function for this leaf node.
94
     *
95
     * @param string[] $ancestors Array of parent properties e.g. ['Orders', 'Customer', 'Customer_Demographics']
96
     *
97
     * @return Closure
98
     */
99
    public function buildComparisonFunction(array $ancestors): callable
100
    {
101
        if (0 == count($ancestors)) {
102
            $msg = Messages::orderByLeafNodeArgumentShouldBeNonEmptyArray();
103
            throw new InvalidArgumentException($msg);
104
        }
105
106
        $ascend = $this->isAscending ? 1 : -1;
107
108
        $retVal = function ($object1, $object2) use ($ancestors, $ascend) {
109
            $accessor1 = $object1;
110
            $accessor2 = $object2;
111
            $flag1     = null === $accessor1;
112
            $flag2     = null === $accessor2;
113
            foreach ($ancestors as $i => $ancestor) {
114
                if ($i == 0) {
115
                    continue;
116
                }
117
                $accessor1 = $accessor1->{$ancestor};
118
                $accessor2 = $accessor2->{$ancestor};
119
                $flag1 |= null === $accessor1;
120
                $flag2 |= null === $accessor2;
121
            }
122
            $propertyName = $this->propertyName;
123
            $getter       = 'get' . ucfirst($propertyName);
124
            if (null !== $accessor1) {
125
                $accessor1 = method_exists($accessor1, $getter) ? $accessor1->{$getter}() : $accessor1->{$propertyName};
126
            }
127
            if (null !== $accessor2) {
128
                $accessor2 = method_exists($accessor2, $getter) ? $accessor2->{$getter}() : $accessor2->{$propertyName};
129
            }
130
131
            $flag1 |= null === $accessor1;
132
            $flag2 |= null === $accessor2;
133
134
            if ($flag1 && $flag2) {
135
                return 0;
136
            } elseif ($flag1) {
137
                return $ascend * -1;
138
            } elseif ($flag2) {
139
                return $ascend * 1;
140
            }
141
            $type = $this->resourceProperty->getInstanceType();
142
            if ($type instanceof DateTime) {
143
                $result = strtotime($accessor1) - strtotime($accessor2);
144
            } elseif ($type instanceof StringType) {
145
                $result = strcmp($accessor1, $accessor2);
146
            } elseif ($type instanceof Guid) {
147
                $result = strcmp($accessor1, $accessor2);
148
            } else {
149
                $delta  = $accessor1 - $accessor2;
150
                $result = (0 == $delta) ? 0 : $delta / abs($delta);
151
            }
152
153
            return $ascend * $result;
154
        };
155
156
        return $retVal;
157
    }
158
}
159