Completed
Push — milestone/2_0/react-ui ( 1c376a...57d10c )
by
unknown
02:51
created

Widget::verify_unique_widget_id()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 7
rs 9.4285
1
<?php
2
3
namespace Carbon_Fields\Widget;
4
5
use Carbon_Fields\Helper\Helper;
6
use Carbon_Fields\Field\Field;
7
use Carbon_Fields\Container\Container;
8
use Carbon_Fields\Datastore\Datastore;
9
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
10
11
/**
12
 * Widget, datastore and container handler class.
13
 */
14
abstract class Widget extends \WP_Widget {
15
	public static $registered_widget_ids = array();
16
17
	/**
18
	 * Widget Datastore
19
	 *
20
	 * @var Widget_Datastore
21
	 */
22
	protected $datastore;
23
24
	/**
25
	 * Determines if widget wrapper html should be printed
26
	 *
27
	 * @see widget()
28
	 * @var bool
29
	 */
30
	protected $print_wrappers = true;
31
32
	/**
33
	 * Control options to pass to WordPress Widget constructor
34
	 *
35
	 * @see setup()
36
	 * @var array
37
	 */
38
	protected $widget_control_options = array( 'width' => 295 );
39
40
	/**
41
	 * Array of Carbon Fields for the widget
42
	 *
43
	 * @var array
44
	 */
45
	protected $custom_fields = array();
46
47
	/**
48
	 * Create the widget.
49
	 * A wrapper around the default WP widget constructor.
50
	 *
51
	 * @param  string $title       Widget name
52
	 * @param  string $description Widget description
53
	 * @param  array $fields       Array of fields
54
	 * @param  string $classname   String of CSS classes
55
	 */
56
	public function setup( $title, $description, $fields, $classname = '' ) {
57
		\Carbon_Fields\Carbon_Fields::verify_boot();
58
		
59
		$this->datastore = Datastore::make( 'widget' );
0 ignored issues
show
Documentation Bug introduced by
It seems like \Carbon_Fields\Datastore...tastore::make('widget') can also be of type object<Carbon_Fields\Dat...re\Datastore_Interface>. However, the property $datastore is declared as type object<Carbon_Fields\Widget\Widget_Datastore>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
60
		if ( empty( $title ) ) {
61
			Incorrect_Syntax_Exception::raise( 'Empty widget title is not supported' );
62
		}
63
64
		$this->add_fields( $fields );
65
66
		# Generate Widget ID
67
		$widget_id = 'carbon_widget_' . preg_replace( '~\s+~', '_', strtolower( trim( preg_replace( '/[^a-zA-Z0-9]+/u', '', remove_accents( $title ) ) ) ) );
68
69
		$this->register_widget_id( $widget_id );
70
71
		# Generate Classes
72
		if ( ! is_array( $classname ) ) {
73
			$classname = (array) $classname;
74
		}
75
		$classname[] = $widget_id;
76
		$classname = array_filter( $classname );
77
		$classname = implode( ' ', $classname );
78
79
		$widget_options = array(
80
			'description' => $description,
81
			'classname' => $classname,
82
			'widget_ID' => $widget_id,
83
		);
84
85
		parent::__construct( $widget_id, $title, $widget_options, $this->widget_control_options );
86
	}
87
88
	/**
89
	 * Updates a particular instance of a widget.
90
	 *
91
	 * @param array $new_instance New settings for this instance as input by the user via
92
	 *                            WP_Widget::form().
93
	 * @param array $old_instance Old settings for this instance.
94
	 * @return array Settings to save or bool false to cancel saving.
95
	 */
96
	public function update( $new_instance, $old_instance ) {
97
		$this->datastore->import_storage( $old_instance );
98
99
		foreach ( $this->custom_fields as $field ) {
100
			$field->set_value_from_input( $new_instance );
101
			$field->save();
102
		}
103
104
		return $this->datastore->export_storage();
105
	}
106
107
	/**
108
	 * Outputs the settings update form.
109
	 *
110
	 * @param array $instance Current settings.
111
	 */
112
	public function form( $instance ) {
113
		$this->datastore->import_storage( $instance );
114
		$custom_fields = array();
115
116
		foreach ( $this->custom_fields as $field ) {
117
			$tmp_field = clone $field;
118
			$tmp_field->load();
119
120
			$field_name = $this->get_field_name( $tmp_field->get_name() );
121
			$tmp_field->set_name( $field_name );
122
123
			$custom_fields[] = $tmp_field;
124
		}
125
126
		Container::factory( 'widget', $this->id )
127
			->add_fields( $custom_fields )
128
			->init();
129
	}
130
131
	/**
132
	 * Echoes the widget content.
133
	 * Sub-classes can over-ride this method to generate their widget code
134
	 * but it is best to override front_end().
135
	 *
136
	 * @param array $args     Display arguments including 'before_title', 'after_title',
137
	 *                        'before_widget', and 'after_widget'.
138
	 * @param array $instance The settings for the particular instance of the widget.
139
	 */
140
	public function widget( $args, $instance ) {
141
		if ( $this->print_wrappers ) {
142
			echo $args['before_widget'];
143
		}
144
145
		$this->front_end( $args, $instance );
146
147
		if ( $this->print_wrappers ) {
148
			echo $args['after_widget'];
149
		}
150
	}
151
152
	/**
153
	 * The actual content of the widget.
154
	 * Generally should be overriden by the specific widget classes.
155
	 * @param array $args     Display arguments including 'before_title', 'after_title',
156
	 *                        'before_widget', and 'after_widget'.
157
	 * @param array $instance The settings for the particular instance of the widget.
158
	 */
159
	public function front_end( $args, $instance ) { }
160
161
	/**
162
	 * Append array of fields to the current fields set. All items of the array
163
	 * must be instances of Field and their names should be unique for all
164
	 * Carbon containers.
165
	 *
166
	 * @param array $fields
167
	 **/
168
	public function add_fields( $fields ) {
169
		foreach ( $fields as $field ) {
170
			if ( ! is_a( $field, 'Carbon_Fields\\Field\\Field' ) ) {
171
				Incorrect_Syntax_Exception::raise( 'Object must be of type Carbon_Fields\\Field\\Field' );
172
				return;
173
			}
174
			$this->register_field_name( $field->get_name() );
175
			$field->set_name_prefix( '' );
176
			$field->set_datastore( $this->datastore, true );
177
		}
178
		$this->custom_fields = array_merge( $this->custom_fields, $fields );
179
	}
180
181
	/**
182
	 * Verify widget field names are unique.
183
	 *
184
	 * @param  string $name Field name
185
	 * @return boolean
186
	 */
187
	public function register_field_name( $name ) {
188
		static $registered_field_names = array();
189
190
		if ( in_array( $name, $registered_field_names ) ) {
191
			Incorrect_Syntax_Exception::raise( 'Field name "' . $name . '" already registered' );
192
			return false;
193
		}
194
195
		$registered_field_names[] = $name;
196
		return true;
197
	}
198
199
	/**
200
	 * Verify widget IDs are unique.
201
	 *
202
	 * @param  string $id Widget ID
203
	 */
204
	public function register_widget_id( $id ) {
205
		if ( in_array( $id, static::$registered_widget_ids ) ) {
206
			Incorrect_Syntax_Exception::raise( 'Widget with ID "' . $id . '" already registered. Please change the widget title' );
207
			return;
208
		}
209
210
		static::$registered_widget_ids[] = $id;
211
	}
212
}
213