Completed
Push — master ( ab4944...534e9c )
by Andrew
02:30
created

ClassyMenu   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 169
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 2
Bugs 0 Features 2
Metric Value
c 2
b 0
f 2
dl 0
loc 169
rs 10
wmc 27
lcom 1
cbo 1

6 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 27 6
B init() 0 28 6
A get_first_menu_id() 0 17 4
B check_menu_id() 0 21 5
B get_menu_id_by_name() 0 17 5
A get_items() 0 5 1
1
<?php
2
3
/**
4
 * Class for handling menu functionality
5
 */
6
7
class ClassyMenu {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
8
9
	/**
10
	 * Menu ID
11
	 * @var int
12
	 */
13
	public $ID;
14
15
	/**
16
	 * Items
17
	 * @var array
18
	 */
19
	protected $items;
20
21
	/**
22
	 * Main constructor. Tries to find menu id based on provided arg (or not) and inits menu
23
	 * 
24
	 * @param string $arg it can be menu id, slug or full name
25
	 */
26
	public function __construct($arg = null) {
27
28
		if (is_numeric($arg) && $arg != 0) {
29
30
			$menu_id = $this->check_menu_id($arg);
31
32
		} elseif (is_string($arg)) {
33
34
			$menu_id = $this->get_menu_id_by_name($arg);
35
36
		}
37
38
		if (!isset($menu_id)) {
39
			
40
			$menu_id = $this->get_first_menu_id();
41
42
		}
43
44
		if ($menu_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $menu_id of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
45
46
			$this->ID = $menu_id;
47
48
			$this->init();
49
50
		}
51
52
	}
53
54
	/**
55
	 * Inits menu
56
	 * 
57
	 * @return void
58
	 */
59
	protected function init() {
60
61
		$_return = array();
62
63
		$items = wp_get_nav_menu_items($this->ID);
64
65
		foreach ($items as $item) {
66
67
			$_return[$item->ID] = new ClassyMenuItem($item);
68
		}
69
70
		// Apply nesting
71
72
		foreach ($_return as $item_id => $item) {
73
			
74
			if (isset($item->menu_item_parent) && $item->menu_item_parent && isset($_return[$item->menu_item_parent])) {
75
			
76
				$_return[$item->menu_item_parent]->add_child($item);
77
78
				unset($_return[$item_id]);
79
			
80
			}
81
82
		}
83
84
		$this->items = $_return;
85
86
	}
87
88
	/**
89
	 * Retuns first menu id or false if there are no menus
90
	 * 
91
	 * @return int
92
	 */
93
	protected function get_first_menu_id() {
94
95
		$menus = get_terms('nav_menu', array('hide_empty' => true));
96
		
97
		if (is_array($menus) && count($menus)) {
98
99
			if (isset($menus[0]->term_id)) {
100
101
				return $menus[0]->term_id;
102
			
103
			}
104
		
105
		}
106
107
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by ClassyMenu::get_first_menu_id of type integer.

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...
108
109
	}
110
111
	/**
112
	 * Checks if the provided menu id exists
113
	 * 
114
	 * @param  int $menu_id 
115
	 * @return int/boolean          
0 ignored issues
show
Documentation introduced by
The doc-type int/boolean could not be parsed: Unknown type name "int/boolean" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
116
	 */
117
	protected function check_menu_id($menu_id) {
118
119
		$menus = get_terms('nav_menu', array('hide_empty' => true));
120
		
121
		if (is_array($menus) && count($menus)) {
122
123
			foreach ($menus as $menu) {
124
125
				if ($menu->term_id == $menu_id) {
126
127
					return $menu_id;
128
129
				}
130
131
			}
132
		
133
		}
134
135
		return false;
136
137
	}
138
139
	/**
140
	 * Returns menu id by menu name/slug
141
	 * 
142
	 * @param  string $slug 
143
	 * @return int
144
	 */
145
	protected function get_menu_id_by_name($slug = null) {
146
147
		if ($slug && is_string($slug)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $slug of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
148
			
149
			$menu_id = get_term_by('slug', $slug, 'nav_menu');
150
151
			if ($menu_id) return $menu_id;
152
153
			$menu_id = get_term_by('name', $slug, 'nav_menu');
154
			
155
			if ($menu_id) return $menu_id;
156
157
		}
158
159
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by ClassyMenu::get_menu_id_by_name of type integer.

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...
160
	
161
	}
162
163
	/**
164
	 * Returns menu items
165
	 * 
166
	 * @return array
167
	 */
168
	public function get_items() {
169
170
		return $this->items;
171
172
	}
173
174
175
}