Completed
Push — master ( e84808...5a9d2e )
by Oleg
07:58
created

Link   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 150
Duplicated Lines 14.67 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 11
c 3
b 0
f 0
lcom 1
cbo 8
dl 22
loc 150
ccs 54
cts 54
cp 1
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
A render() 0 6 1
A buildAttributes() 0 7 2
A renderWith() 0 11 1
A isUrlEqual() 0 15 2
A wakeupCurrentUrl() 0 5 1
A toArray() 11 11 1
A unserialize() 0 6 1
A propertiesForSerialization() 11 11 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
namespace Malezha\Menu\Element;
3
4
use Illuminate\Container\Container;
5
use Illuminate\Http\Request;
6
use Malezha\Menu\Contracts\Attributes;
7
use Malezha\Menu\Contracts\DisplayRule as DisplayRuleInterface;
8
use Malezha\Menu\Contracts\HasAttributes as HasAttributesInterface;
9
use Malezha\Menu\Contracts\HasActiveAttributes as HasActiveAttributesInterface;
10
use Malezha\Menu\Contracts\MenuRender;
11
use Malezha\Menu\Support\MergeAttributes;
12
use Malezha\Menu\Traits\DisplayRule;
13
use Malezha\Menu\Traits\HasActiveAttributes;
14
use Malezha\Menu\Traits\HasAttributes;
15
16
/**
17
 * Class Link
18
 * @package Malezha\Menu\Element
19
 *
20
 * @property string $title
21
 * @property string $url
22
 * @property-read Attributes $attributes
23
 * @property-read Attributes $linkAttributes
24
 * @property-read Attributes $activeAttributes
25
 * @property bool|callable $displayRule
26
 */
27
class Link extends AbstractElement implements DisplayRuleInterface, HasAttributesInterface, HasActiveAttributesInterface
28
{
29
    use DisplayRule, HasAttributes, HasActiveAttributes;
30
31
    /**
32
     * @var string
33
     */
34
    protected $title;
35
36
    /**
37
     * @var string
38
     */
39
    protected $url;
40
41
    /**
42
     * @var Attributes
43
     */
44
    protected $linkAttributes;
45
46
    /**
47
     * @var string
48
     */
49
    protected $currentUrl;
50
51
    /**
52
     * Link constructor.
53
     * @param string $title
54
     * @param string $url
55
     * @param Attributes $attributes
56
     * @param Attributes $activeAttributes
57
     * @param Attributes $linkAttributes
58
     * @param string $view
59
     * @param string $currentUrl
60
     * @param MenuRender $render
61
     */
62 18
    public function __construct($title, $url, Attributes $attributes, Attributes $activeAttributes, 
63
                                Attributes $linkAttributes, $view, $currentUrl, MenuRender $render)
64
    {
65 18
        $this->title = $title;
66 18
        $this->url = $url;
67 18
        $this->attributes = $attributes;
68 18
        $this->activeAttributes = $activeAttributes;
69 18
        $this->linkAttributes = $linkAttributes;
70 18
        $this->view = $view;
71 18
        $this->currentUrl = $currentUrl;
72 18
        $this->render = $render;
73 18
    }
74
75
    /**
76
     * @inheritdoc
77
     */
78 8
    public function render($view = null)
79
    {
80 8
        return $this->render->make($this->view)
81 8
            ->with($this->renderWith())
82 8
            ->render();
83
    }
84
85
    /**
86
     * @inheritDoc
87
     */
88 8
    public function buildAttributes($attributes = [])
89
    {
90 8
        $attributes = $this->isUrlEqual($this->url, $this->currentUrl) ?
91 8
            (new MergeAttributes($this->activeAttributes->all(), $attributes))->merge() : $attributes;
92
93 8
        return $this->attributes->build($attributes);
94
    }
95
96
    /**
97
     * @return array
98
     */
99 8
    protected function renderWith()
100
    {
101
        return [
102 8
            'title' => $this->title,
103 8
            'url' => $this->url,
104 8
            'attributes' => $this->buildAttributes(),
105 8
            'linkAttributes' => $this->linkAttributes->build(),
106 8
            'canDisplay' => $this->canDisplay(),
107
            'renderView' => null,
108
        ];
109
    }
110
111
    /**
112
     * Check is two url equal
113
     *
114
     * @param string $first
115
     * @param string $second
116
     * @return bool
117
     */
118 8
    protected function isUrlEqual($first, $second)
119
    {
120
        $uriForTrim = [
121 8
            '#',
122
            '/index',
123
            '/',
124
        ];
125
126 8
        foreach ($uriForTrim as $trim) {
127 8
            $first = rtrim($first, $trim);
128 8
            $second = rtrim($second, $trim);
129
        }
130
131 8
        return $first == $second;
132
    }
133
    
134 1
    protected function wakeupCurrentUrl()
135
    {
136 1
        $app = Container::getInstance();
137 1
        $this->currentUrl = $app->make(Request::class)->url();
138 1
    }
139
140
    /**
141
     * @inheritDoc
142
     */
143 2 View Code Duplication
    public function toArray()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
144
    {
145 2
        return array_merge(parent::toArray(), [
0 ignored issues
show
Best Practice introduced by
The expression return array_merge(paren... $this->canDisplay())); seems to be an array, but some of its elements' types (array|boolean) are incompatible with the return type of the parent method Malezha\Menu\Element\AbstractElement::toArray of type array<string,string>.

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 new Author('Johannes');
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return '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...
146 2
            'title' => $this->title,
147 2
            'url' => $this->url,
148 2
            'attributes' => $this->attributes->toArray(),
149 2
            'activeAttributes' => $this->activeAttributes->toArray(),
150 2
            'linkAttributes' => $this->linkAttributes->toArray(),
151 2
            'displayRule' => $this->canDisplay(),
152
        ]);
153
    }
154
155
    /**
156
     * @inheritDoc
157
     */
158 1
    public function unserialize($serialized)
159
    {
160 1
        $this->wakeupCurrentUrl();
161
162 1
        parent::unserialize($serialized);
163 1
    }
164
165 2 View Code Duplication
    protected function propertiesForSerialization()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
166
    {
167 2
        return array_merge(parent::propertiesForSerialization(), [
0 ignored issues
show
Best Practice introduced by
The expression return array_merge(paren...his->serializeRule())); seems to be an array, but some of its elements' types (Malezha\Menu\Contracts\Attributes) are incompatible with the return type of the parent method Malezha\Menu\Element\Abs...pertiesForSerialization of type array<string,string>.

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 new Author('Johannes');
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return '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...
168 2
            'title' => $this->title,
169 2
            'url' => $this->url,
170 2
            'attributes' => $this->attributes,
171 2
            'activeAttributes' => $this->activeAttributes,
172 2
            'linkAttributes' => $this->linkAttributes,
173 2
            'displayRule' => $this->serializeRule(),
174
        ]);
175
    }
176
}