Completed
Pull Request — master (#204)
by Vitor
03:32
created

TelegramInlineView   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 266
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 89.94%

Importance

Changes 0
Metric Value
wmc 45
lcom 1
cbo 1
dl 0
loc 266
ccs 143
cts 159
cp 0.8994
rs 8.3673
c 0
b 0
f 0

26 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 2
A createDefaultTemplate() 0 4 1
A render() 0 9 1
A initializePagerfanta() 0 8 1
A initializeOptions() 0 6 2
A getDefaultProximity() 0 10 2
A configureTemplate() 0 5 1
A generatePages() 0 14 1
A calculateStartAndEndPage() 0 18 3
A startPageUnderflow() 0 4 1
A endPageOverflow() 0 4 1
A calculateEndPageForStartPageUnderflow() 0 4 1
A calculateStartPageForEndPageOverflow() 0 4 1
A previous() 0 12 3
A first() 0 12 3
A pages() 0 8 3
A page() 0 12 2
A pushNewButton() 0 6 1
A pageOfPreviousButton() 0 6 1
A pageExists() 0 3 1
A toLast() 0 4 1
A last() 0 20 4
B next() 0 18 5
A setMaxButtons() 0 4 1
A getName() 0 4 1
A __toString() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like TelegramInlineView often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TelegramInlineView, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Pagerfanta\View;
3
use Pagerfanta\View\ViewInterface;
4
use Pagerfanta\PagerfantaInterface;
5
use Pagerfanta\View\Template\TemplateInterface;
6
use TelegramPagerfanta\View\Template\TelegramInlineTemplate;
7
8
class TelegramInlineView implements ViewInterface
9
{
10
    /**
11
     * @var TelegramInlineTemplate
12
     */
13
    private $template;
14
15
    /**
16
     * @var PagerfantaInterface
17
     */
18
    private $pagerfanta;
19
20
    private $currentPage;
21
    private $nbPages;
22
23
    private $startPage;
24
    private $endPage;
25
    private $maxPerPage;
26
    
27
    private $buttons;
28
    
29
    private $maxButtons;
30
31 10
    public function __construct(TemplateInterface $template = null)
32
    {
33 10
        $this->template = $template ?: $this->createDefaultTemplate();
0 ignored issues
show
Documentation Bug introduced by
It seems like $template ?: $this->createDefaultTemplate() of type object<Pagerfanta\View\T...late\TemplateInterface> is incompatible with the declared type object<TelegramPagerfant...TelegramInlineTemplate> of property $template.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
34 10
        $this->buttons = new \stdClass();
35 10
    }
36
37 10
    protected function createDefaultTemplate()
38
    {
39 10
        return new \Pagerfanta\View\Template\TelegramInlineTemplate();
40
    }
41
42 10
    public function render(PagerfantaInterface $pagerfanta, $routeGenerator, array $options = array())
43
    {
44 10
        $this->initializePagerfanta($pagerfanta);
45 10
        $this->initializeOptions($options);
46
47 10
        $this->configureTemplate($routeGenerator, $options);
48
49 10
        return $this->generatePages();
50
    }
51
52 10
    private function initializePagerfanta(PagerfantaInterface $pagerfanta)
53
    {
54 10
        $this->pagerfanta = $pagerfanta;
55
56 10
        $this->currentPage = $pagerfanta->getCurrentPage();
57 10
        $this->nbPages = $pagerfanta->getNbPages();
58 10
        $this->maxPerPage = $pagerfanta->getMaxPerPage();
59 10
    }
60
61 10
    private function initializeOptions($options)
62
    {
63 10
        $this->proximity = isset($options['proximity']) ?
0 ignored issues
show
Bug introduced by
The property proximity does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
64 10
                           (int) $options['proximity'] :
65 9
                           $this->getDefaultProximity();
66 10
    }
67
68 9
    protected function getDefaultProximity()
69
    {
70 9
        $proximityEstimated = floor($this->maxPerPage / 2);
71 9
        if($proximityEstimated < 2) {
72
            $proximity = $proximityEstimated;
73
        } else {
74 9
            $proximity = 2;
75
        }
76 9
        return $proximity;
77
    }
78
79 10
    private function configureTemplate($routeGenerator, $options)
80
    {
81 10
        $this->template->setRouteGenerator($routeGenerator);
82 10
        $this->template->setOptions($options);
83 10
    }
84
85 10
    private function generatePages()
86
    {
87 10
        $this->calculateStartAndEndPage();
88
89 10
        $this->page($this->currentPage);
90 10
        $this->first();
91 10
        $this->last();
92 10
        $this->previous();
93 10
        $this->next();
94 10
        $this->pages();
95 10
        ksort($this->buttons->inline_keyboard[0]);
96 10
        $this->buttons->inline_keyboard[0] = array_values($this->buttons->inline_keyboard[0]);
97 10
        return (string)$this;
98
    }
99
100 10
    private function calculateStartAndEndPage()
101
    {
102 10
        $startPage = $this->currentPage - $this->proximity;
103 10
        $endPage = $this->currentPage + $this->proximity;
104
105 10
        if ($this->startPageUnderflow($startPage)) {
106 2
            $startPage = 1;
107 2
            $endPage = $this->maxPerPage;
108 2
            $endPage = $this->calculateEndPageForStartPageUnderflow($startPage, $endPage);
109 2
        }
110 10
        if ($this->endPageOverflow($endPage)) {
111 1
            $startPage = $this->calculateStartPageForEndPageOverflow($startPage, $endPage);
112 1
            $endPage = $this->nbPages;
113 1
        }
114
115 10
        $this->startPage = $startPage;
116 10
        $this->endPage = $endPage;
117 10
    }
118
119 10
    private function startPageUnderflow($startPage)
120
    {
121 10
        return $startPage < 1;
122
    }
123
124 10
    private function endPageOverflow($endPage)
125
    {
126 10
        return $endPage > $this->nbPages;
127
    }
128
129 2
    private function calculateEndPageForStartPageUnderflow($startPage, $endPage)
130
    {
131 2
        return min($endPage + (1 - $startPage), $this->nbPages);
132
    }
133
134 1
    private function calculateStartPageForEndPageOverflow($startPage, $endPage)
135
    {
136 1
        return max($startPage - ($endPage - $this->nbPages), 1);
137
    }
138
139 10
    private function previous()
140
    {
141 10
        if ($this->currentPage > $this->maxPerPage) {
142 3
            $prev = $this->startPage;
143 3
            if($this->startPage+$this->maxPerPage-1 >= $this->nbPages) {
144 3
                $prev--;
145 3
            }
146 3
            $this->pushNewButton(
147 3
                $this->template->previousEnabled($prev)
148 3
            );
149 3
        }
150 10
    }
151
152 10
    private function first()
153
    {
154 10
        if(!$this->pageExists(1)) {
155 8
            if($this->currentPage > $this->maxPerPage) {
156 3
                $this->pushNewButton(
157 3
                    $this->template->first()
158 3
                );
159 3
            } else {
160 5
                $this->page(1);
161
            }
162 8
        }
163 10
    }
164
165 10
    private function pages()
166
    {
167 10
        foreach (range($this->startPage, $this->endPage) as $page) {
168 10
            if(!$this->pageExists($page)) {
169 10
                $this->page($page);
170 10
            }
171 10
        }
172 10
    }
173
174 10
    private function page($page)
175
    {
176 10
        if ($page == $this->currentPage) {
177 10
            $this->pushNewButton(
178 10
                $this->template->current($page)
179 10
            );
180 10
        } else {
181 10
            $this->pushNewButton(
182 10
                $this->template->page($page)
183 10
            );
184
        }
185 10
    }
186
    
187 10
    private function pushNewButton(array $params) {
188 10
        $params = (object)$params;
189 10
        $page = $params->page;
190 10
        unset($params->page);
191 10
        $this->buttons->inline_keyboard[0][$page] = $params;
192 10
    }
193
    
194
    private function pageOfPreviousButton()
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
195
    {
196
        $keys = array_keys($this->buttons->inline_keyboard[0]);
197
        array_pop($keys);
198
        return array_pop($keys);
199
    }
200
201 10
    private function pageExists($page) {
202 10
        return isset($this->buttons->inline_keyboard[0][$page]);
203
    }
204
205
    private function toLast($n)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
206
    {
207
        return $this->pagerfanta->getNbPages() - ($n - 1);
208
    }
209
210 10
    private function last()
211
    {
212 10
        if ($this->nbPages > $this->endPage) {
213 9
            if($this->nbPages - $this->endPage <= 1) {
214 1
                $this->pushNewButton(
215 1
                    $this->template->page($this->nbPages)
216 1
                );
217 1
            } else {
218 8
                if($this->endPage +2 >= $this->nbPages) {
219 1
                    $this->pushNewButton(
220 1
                        $this->template->page($this->nbPages)
221 1
                    );
222 1
                } else {
223 7
                    $this->pushNewButton(
224 7
                        $this->template->last($this->nbPages)
225 7
                    );
226
                }
227
            }
228 9
        }
229 10
    }
230
231 10
    private function next()
232
    {
233 10
        if ($this->pagerfanta->hasNextPage()) {
234 9
            $next = $this->endPage;
235 9
            if($this->pageExists($next) || $next == $this->maxPerPage) {
236 2
                $next++;
237 2
            }
238 9
            if($next < $this->nbPages) {
239 9
                $this->pushNewButton(
240 9
                    $this->template->nextEnabled($next)
241 9
                );
242 9
            } else {
243
                $this->pushNewButton(
244
                    $this->template->page($next)
245
                );
246
            }
247 9
        }
248 10
    }
249
    
250
    public function setMaxButtons($max)
251
    {
252
        $this->maxButtons = $max;
253
    }
254
255
    /**
256
     * {@inheritdoc}
257
     */
258
    public function getName()
259
    {
260
        return 'TelegramInline';
261
    }
262
    
263
264
    /**
265
     * Convert the collection to its string representation.
266
     *
267
     * @return string
268
     */
269 10
    public function __toString()
270
    {
271 10
        return json_encode($this->buttons, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
272
    }
273
}
274