Completed
Push — master ( 189bb6...0d32b3 )
by Matthew
03:08
created

AlertStatisticsLoader::readHistorySummary()   C

Complexity

Conditions 8
Paths 45

Size

Total Lines 77
Code Lines 45

Duplication

Lines 14
Ratio 18.18 %

Importance

Changes 2
Bugs 1 Features 1
Metric Value
c 2
b 1
f 1
dl 14
loc 77
rs 6.1477
cc 8
eloc 45
nc 45
nop 1

How to fix   Long Method   

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
namespace Ps2alerts\Api\Loader\Statistics;
4
5
use Ps2alerts\Api\Loader\Statistics\AbstractStatisticsLoader;
6
use Ps2alerts\Api\QueryObjects\QueryObject;
7
use Ps2alerts\Api\Repository\AlertRepository;
8
use Ps2alerts\Api\Validator\AlertInputValidator;
9
use Ps2alerts\Api\Helper\DataFormatterHelper;
10
11
class AlertStatisticsLoader extends AbstractStatisticsLoader
12
{
13
    /**
14
     * @var \Ps2alerts\Api\Repository\AlertRepository
15
     */
16
    protected $repository;
17
18
    /**
19
     * @var \Ps2alerts\Api\Helper\DataFormatterHelper
20
     */
21
    protected $dataFormatter;
22
23
    /**
24
     * Construct
25
     *
26
     * @param \Ps2alerts\Api\Repository\AlertRepository    $repository
27
     * @param \Ps2alerts\Api\Helper\DataFormatter          $dataFormatter
28
     */
29
    public function __construct(
30
        AlertRepository     $repository,
31
        DataFormatterHelper $dataFormatter
32
    ) {
33
        $this->repository     = $repository;
34
        $this->dataFormatter  = $dataFormatter;
35
36
        $this->setCacheNamespace('Statistics');
37
        $this->setType('Alerts');
38
    }
39
40
    /**
41
     * Read total counts for alerts
42
     *
43
     * @param  array $post
44
     *
45
     * @return array
46
     */
47
    public function readTotals(array $post)
48
    {
49
        $redisKey = "{$this->getCacheNamespace()}:{$this->getType()}:Totals";
50
        $redisKey = $this->appendRedisKey($post, $redisKey);
51
        $post = $this->processPostVars($post);
52
53
        $this->getLogDriver()->addDebug($redisKey);
54
55
        if ($this->checkRedis($redisKey)) {
56
            return $this->getFromRedis($redisKey);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getFromRedis($redisKey); (string) is incompatible with the return type documented by Ps2alerts\Api\Loader\Sta...sticsLoader::readTotals 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...
57
        }
58
59
        $queryObject = new QueryObject;
60
        $queryObject = $this->setupQueryObject($queryObject, $post);
61
62
        $queryObject->addSelect('COUNT(ResultID) AS COUNT');
63
64
        if ($this->checkRedis($redisKey)) {
65
            return $this->getFromRedis($redisKey);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getFromRedis($redisKey); (string) is incompatible with the return type documented by Ps2alerts\Api\Loader\Sta...sticsLoader::readTotals 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...
66
        }
67
68
        $this->setCacheExpireTime(900); // 15 mins
69
70
        return $this->cacheAndReturn(
71
            $this->repository->read($queryObject),
72
            $redisKey
73
        );
74
    }
75
76
    /**
77
     * Retrieves all zone totals and caches as required
78
     *
79
     * @return array
80
     */
81
    public function readZoneTotals()
82
    {
83
        $masterRedisKey = "{$this->getCacheNamespace()}:{$this->getType()}:Totals:Zones";
84
85
        $this->getLogDriver()->addDebug($masterRedisKey);
86
87
        if ($this->checkRedis($masterRedisKey)) {
88
            $this->getLogDriver()->addDebug("Pulled the lot from Redis");
89
            return $this->getFromRedis($masterRedisKey);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getFromRedis($masterRedisKey); (string) is incompatible with the return type documented by Ps2alerts\Api\Loader\Sta...sLoader::readZoneTotals 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...
90
        }
91
92
        $servers  = [1,10,13,17,25,1000,2000];
93
        $zones    = [2,4,6,8];
94
        $factions = ['vs','nc','tr','draw'];
95
96
        $results = [];
97
        $this->setCacheExpireTime(3600); // 1 Hour
98
99
        // Dat loop yo
100
        foreach ($servers as $server) {
101
            foreach ($zones as $zone) {
102
                foreach ($factions as $faction) {
103
                    $results[$server][$zone][$faction] = $this->getZoneStats($server, $zone, $faction);
104
                }
105
            }
106
        }
107
108
        // Commit to Redis
109
        return $this->cacheAndReturn(
110
            $results,
111
            $masterRedisKey
112
        );
113
    }
114
115
    /**
116
     * Gets all information regarding zone victories out of the DB and caches as
117
     * required
118
     *
119
     * @see readZoneTotals()
120
     *
121
     * @param  integer $server
122
     * @param  integer $zone
123
     * @param  integer $faction
124
     *
125
     * @return array
126
     */
127
    public function getZoneStats($server, $zone, $faction)
128
    {
129
        $redisKey = "{$this->getCacheNamespace()}:{$this->getType()}:Totals:Zones";
130
        $redisKey .= ":{$server}:{$zone}:{$faction}";
131
132
        $this->getLogDriver()->addDebug($redisKey);
133
134
        if ($this->checkRedis($redisKey)) {
135
            $this->getLogDriver()->addDebug("CACHE PULL");
136
            return $this->getFromRedis($redisKey);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getFromRedis($redisKey); (string) is incompatible with the return type documented by Ps2alerts\Api\Loader\Sta...icsLoader::getZoneStats 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...
137
        }
138
139
        // Fire a set of queries to build the object required
140
        $queryObject = new QueryObject;
141
        $queryObject->addSelect('COUNT(ResultID) AS COUNT');
142
        $queryObject->addWhere([
143
            'col'   => 'ResultServer',
144
            'value' => $server
145
        ]);
146
        $queryObject->addWhere([
147
            'col'   => 'ResultAlertCont',
148
            'value' => $zone
149
        ]);
150
        $queryObject->addWhere([
151
            'col'   => 'ResultWinner',
152
            'value' => $faction
153
        ]);
154
155
        // Commit to Redis
156
        return $this->cacheAndReturn(
157
            $this->repository->read($queryObject)[0]["COUNT"],
158
            $redisKey
159
        );
160
    }
161
162
    /**
163
     * Generates the data required for History Summaries
164
     *
165
     * @param  array $post
166
     *
167
     * @return array
168
     */
169
    public function readHistorySummary(array $post)
170
    {
171
        $redisKey = "{$this->getCacheNamespace()}:{$this->getType()}:History";
172
        $redisKey = $this->appendRedisKey($post, $redisKey);
173
        $post = $this->processPostVars($post);
174
175
        $this->getLogDriver()->addDebug($redisKey);
176
177
        $queryObject = new QueryObject;
178
        $queryObject = $this->setupQueryObject($queryObject, $post);
179
        $queryObject->addSelect('FROM_UNIXTIME(ResultEndTime) AS ResultEndTime');
180
        $queryObject->addSelect('ResultWinner');
181
        $queryObject->addWhere([
182
            'col' => 'InProgress',
183
            'value' => 0
184
        ]);
185
        $queryObject->setLimit('unlimited');
186
187
        $minDate = '2014-10-29'; // Beginning of tracking
188
        $maxDate = date('Y-m-d'); // Today unless set
189
190
        // If there is a minimum date set
191 View Code Duplication
        if (! empty($post['wheres']['morethan']['ResultEndTime'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
192
            if (is_integer($post['wheres']['morethan']['ResultEndTime'])) {
193
                $minDate = date('Y-m-d', $post['wheres']['morethan']['ResultEndTime']);
194
            } else {
195
                $minDate = date('Y-m-d', strtotime($post['wheres']['morethan']['ResultEndTime']));
196
            }
197
        }
198
199
        // If there is a maximum date set
200 View Code Duplication
        if (! empty($post['wheres']['lessthan']['ResultEndTime'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
201
            if (is_integer($post['wheres']['lessthan']['ResultEndTime'])) {
202
                $maxDate = date('Y-m-d', $post['wheres']['lessthan']['ResultEndTime']);
203
            } else {
204
                $maxDate = date('Y-m-d', strtotime($post['wheres']['lessthan']['ResultEndTime']));
205
            }
206
        }
207
208
        $redisKey .= "/min-{$minDate}/max-{$maxDate}";
209
210
        if ($this->checkRedis($redisKey)) {
211
            $this->getLogDriver()->addDebug("CACHE PULL");
212
            return $this->getFromRedis($redisKey);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getFromRedis($redisKey); (string) is incompatible with the return type documented by Ps2alerts\Api\Loader\Sta...der::readHistorySummary 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...
213
        }
214
215
        // Get the data to parse
216
        $alerts = $this->repository->read($queryObject);
217
218
        // Generate the range of dates
219
        $dates = $this->dataFormatter->createDateRangeArray($minDate, $maxDate);
220
        $dateRange = [];
221
222
        // Generates the victory totals for each date
223
        foreach ($dates as $date) {
224
            $dateRange[$date] = [
225
                'vs'   => 0,
226
                'nc'   => 0,
227
                'tr'   => 0,
228
                'draw' => 0
229
            ];
230
        }
231
232
        // Calculate metrics
233
        foreach ($alerts as $alert) {
234
            $date = date('Y-m-d', strtotime($alert['ResultEndTime']));
235
            $winner = strtolower($alert['ResultWinner']);
236
237
            $dateRange[$date][$winner]++;
238
        }
239
240
        // Commit to Redis
241
        return $this->cacheAndReturn(
242
            $dateRange,
243
            $redisKey
244
        );
245
    }
246
}
247