Autocomplete   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 171
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 2

Importance

Changes 0
Metric Value
wmc 16
c 0
b 0
f 0
lcom 3
cbo 2
dl 0
loc 171
rs 10

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A setAjaxSource() 0 15 2
A setSource() 0 7 1
A setAutofocus() 0 3 1
A setDelay() 0 3 1
A setDisabled() 0 3 1
A setMinLength() 0 3 1
A setPosition() 0 3 1
A onChange() 0 3 1
A onClose() 0 3 1
A onFocus() 0 3 1
A onOpen() 0 3 1
A onResponse() 0 3 1
A onSearch() 0 3 1
A onSelect() 0 3 1
1
<?php
2
3
namespace Ajax\ui\Components;
4
5
use Ajax\JsUtils;
6
use Phalcon\Text;
7
use Phalcon\Mvc\Url;
8
use Ajax\ui\Properties\Position;
9
use Ajax\common\components\SimpleComponent;
10
11
/**
12
 * JQuery UI Autocomplete component
13
 * @author jc
14
 * @version 1.001
15
 */
16
class Autocomplete extends SimpleComponent {
17
18
	public function __construct(JsUtils $js) {
19
		parent::__construct($js);
20
		$this->uiName="autocomplete";
21
		$this->setParam("minLength", 3);
22
	}
23
24
	/**
25
	 * Define source property with an ajax request based on $url
26
	 * $url must return a JSON array of values
27
	 * @param String $url
28
	 * @return $this
29
	 */
30
	public function setAjaxSource($url) {
31
		if (Text::startsWith($url, "/")) {
32
			$u=$this->js->getDi()->get("url");
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajax\JsUtils as the method getDi() does only exist in the following sub-classes of Ajax\JsUtils: Ajax\php\phalcon\JsUtils. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
33
			$url=$u->getBaseUri().$url;
34
		}
35
		$ajax="%function (request, response) {
36
			$.ajax({
37
				url: '{$url}',
38
				dataType: 'jsonp',
39
				data: {q : request.term},
40
				success: function(data) {response(data);}
41
			});
42
		}%";
43
		return $this->setParam("source", $ajax);
44
	}
45
46
	/**
47
	 * Define the source property
48
	 * with a JSON Array of values
49
	 * Example : ["Bordeaux","Alsace","Bourgogne"]
50
	 * Example : [{value : "BO", label : "Bordeaux"}, {value : "AL", label : "Alsace"}, {value : "BOU", label : "Bourgogne"}]
51
	 * @param String $source
52
	 * @return $this
53
	 */
54
	public function setSource($source) {
55
		$source=str_ireplace(array (
56
				"\"",
57
				"'" 
58
		), "%quote%", $source);
59
		return $this->setParam("source", "%".$source."%");
60
	}
61
62
	/**
63
	 * If set to true the first item will automatically be focused when the menu is shown.
64
	 * default : false
65
	 * @param Boolean $value
66
	 * @return $this
67
	 */
68
	public function setAutofocus($value) {
69
		return $this->setParamCtrl("autoFocus", $value, "is_bool");
70
	}
71
72
	/**
73
	 * The delay in milliseconds between when a keystroke occurs and when a search is performed.
74
	 * A zero-delay makes sense for local data (more responsive), but can produce a lot of load for remote data,
75
	 * while being less responsive.
76
	 * default : 300
77
	 * @param int $value
78
	 * @return $this
79
	 */
80
	public function setDelay($value) {
81
		return $this->setParamCtrl("delay", $value, "is_int");
82
	}
83
84
	/**
85
	 * Disables the autocomplete if set to true.
86
	 * @param Boolean $value default : false
87
	 * @return $this
88
	 */
89
	public function setDisabled($value) {
90
		return $this->setParamCtrl("disabled", $value, "is_bool");
91
	}
92
93
	/**
94
	 * The minimum number of characters a user must type before a search is performed.
95
	 * Zero is useful for local data with just a few items,
96
	 * but a higher value should be used when a single character search could match a few thousand items.
97
	 * @param int $value default : 1
98
	 * @return $this
99
	 */
100
	public function setMinLength($value) {
101
		return $this->setParamCtrl("minLength", $value, "is_int");
102
	}
103
104
	/**
105
	 * Identifies the position of the suggestions menu in relation to the associated input element.
106
	 * The of option defaults to the input element, but you can specify another element to position against.
107
	 * You can refer to the jQuery UI Position utility for more details about the various options.
108
	 * @param int $position default : { my: "left top", at: "left bottom", collision: "none" }
109
	 * @return $this
110
	 */
111
	public function setPosition(Position $position) {
112
		return $this->setParam("position", $position->getParams());
113
	}
114
115
	/**
116
	 * Triggered when the field is blurred, if the value has changed.
117
	 * @param string $jsCode
118
	 * @return $this
119
	 */
120
	public function onChange($jsCode) {
121
		return $this->addEvent("change", $jsCode);
122
	}
123
124
	/**
125
	 * Triggered when the menu is hidden.
126
	 * Not every close event will be accompanied by a change event.
127
	 * @param string $jsCode
128
	 * @return $this
129
	 */
130
	public function onClose($jsCode) {
131
		return $this->addEvent("close", $jsCode);
132
	}
133
134
	/**
135
	 * Triggered when focus is moved to an item (not selecting).
136
	 * The default action is to replace the text field's value with the value of the focused item,
137
	 * though only if the event was triggered by a keyboard interaction.
138
	 * Canceling this event prevents the value from being updated, but does not prevent the menu item from being focused.
139
	 * @param string $jsCode
140
	 * @return $this
141
	 */
142
	public function onFocus($jsCode) {
143
		return $this->addEvent("focus", $jsCode);
144
	}
145
146
	/**
147
	 * Triggered when the suggestion menu is opened or updated.
148
	 * @param string $jsCode
149
	 * @return $this
150
	 */
151
	public function onOpen($jsCode) {
152
		return $this->addEvent("open", $jsCode);
153
	}
154
155
	/**
156
	 * Triggered after a search completes, before the menu is shown.
157
	 * Useful for local manipulation of suggestion data, where a custom source option callback is not required.
158
	 * This event is always triggered when a search completes, even if the menu will not be shown because there are no results or the Autocomplete is disabled.
159
	 * @param string $jsCode
160
	 * @return $this
161
	 */
162
	public function onResponse($jsCode) {
163
		return $this->addEvent("response", $jsCode);
164
	}
165
166
	/**
167
	 * Triggered before a search is performed, after minLength and delay are met.
168
	 * If canceled, then no request will be started and no items suggested.
169
	 * @param string $jsCode
170
	 * @return $this
171
	 */
172
	public function onSearch($jsCode) {
173
		return $this->addEvent("search", $jsCode);
174
	}
175
176
	/**
177
	 * Triggered when an item is selected from the menu.
178
	 * The default action is to replace the text field's value with the value of the selected item.
179
	 * Canceling this event prevents the value from being updated, but does not prevent the menu from closing.
180
	 * @param string $jsCode
181
	 * @return $this
182
	 */
183
	public function onSelect($jsCode) {
184
		return $this->addEvent("select", $jsCode);
185
	}
186
}