Completed
Push — master ( b87221...e5fd41 )
by Askupa
01:26
created

SettingsPage::get_field_value()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Amarkal\Settings;
4
5
/**
6
 * Implements a settings page.
7
 */
8
class SettingsPage
9
{   
0 ignored issues
show
Coding Style introduced by
The opening class brace should be on a newline by itself.
Loading history...
10
    /**
11
     * Configuration array 
12
     * 
13
     * @var array 
14
     */
15
    private $config;
16
    
17
    /**
18
     * The UI form instance
19
     * 
20
     * @var Amarkal\UI\Form 
21
     */
22
    private $form;
23
24
    /**
25
     * The list of arguments for each section 
26
     *
27
     * @var array
28
     */
29
    private $sections;
30
31
    /**
32
     * The list of fields for the entire settings page
33
     *
34
     * @var Amarkal\UI\ComponentList
35
     */
36
    private $fields;
37
    
38
    /**
39
     * Set the config, create a form instance and add actions.
40
     * 
41
     * @param array $config
42
     */
43
    public function __construct( array $config = array() ) 
44
    {
45
        $this->config   = array_merge($this->default_args(), $config);
46
        $this->fields   = new \Amarkal\UI\ComponentList();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Amarkal\UI\ComponentList() of type object<Amarkal\UI\ComponentList> is incompatible with the declared type object<Amarkal\Settings\Amarkal\UI\ComponentList> of property $fields.

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...
47
        $this->sections = array();
48
        $this->form     = new \Amarkal\UI\Form($this->fields);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Amarkal\UI\Form($this->fields) of type object<Amarkal\UI\Form> is incompatible with the declared type object<Amarkal\Settings\Amarkal\UI\Form> of property $form.

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...
49
        
50
        \add_action('admin_menu', array($this,'add_submenu_page'));
51
        \add_action('admin_enqueue_scripts', array($this,'enqueue_scripts'));
52
    }
53
54
    /**
55
     * Add a section to this settings page
56
     *
57
     * @param array $args
58
     * @return void
59
     */
60
    public function add_section( array $args )
61
    {
62
        $args = \array_merge($this->default_section_args(), $args);
63
        $slug = $args['slug'];
64
        if(array_key_exists($slug, $this->sections))
65
        {
66
            throw new \RuntimeException("A section with '$slug' has already been created for this page.");  
67
        }
68
        $this->sections[$slug] = $args;
69
    }
70
71
    /**
72
     * Add a settings field to this settings page
73
     *
74
     * @param array $args
75
     * @return void
76
     */
77
    public function add_field( array $args )
78
    {
79
        $this->fields->add_component($args);
80
    }
81
82
    /**
83
     * Get the value of the given field from the database, or the default value if none exists
84
     *
85
     * @param string $name
86
     * @return void
87
     */
88
    public function get_field_value( $name )
89
    {
90
        $old_instance = $this->get_old_instance();
91
92
        if(\array_key_exists($name, $old_instance))
93
        {
94
            return $old_instance[$name];
95
        }
96
        
97
        $component = $this->get_component($name);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $component is correct as $this->get_component($name) (which targets Amarkal\Settings\SettingsPage::get_component()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
98
        return $component->default;
99
    }
100
    
101
    /**
102
     * Internally used to add a submenu page for this settings page
103
     */
104
    public function add_submenu_page()
105
    {
106
        \add_submenu_page(
107
            $this->config['parent_slug'], 
108
            $this->config['title'], 
109
            $this->config['menu_title'], 
110
            $this->config['capability'],
111
            $this->config['slug'],
112
            array($this, 'render')
113
        );
114
    }
115
    
116
    /**
117
     * Conditionally enqueue settings scripts and styles if the calling page is
118
     * a settings page.
119
     */
120
    public function enqueue_scripts()
121
    {
122
        // Only enqueue styles & scripts if this is a settings page
123
        if($this->config['slug'] === filter_input(INPUT_GET, 'page'))
124
        {
125
            \wp_enqueue_style('amarkal-settings');
126
            \wp_enqueue_script('amarkal-settings');
127
        }
128
    }
129
    
130
    /**
131
     * Render the settings page
132
     */
133
    public function render()
134
    {
135
        $this->form->update($this->get_old_instance());
136
        include __DIR__.'/SettingsPage.phtml';
137
        \add_filter('admin_footer_text', array($this, 'footer_credits'));
138
    }
139
    
140
    /**
141
     * Ajax callback internally used to update options values for the given 
142
     * settings page.
143
     * 
144
     * @param array $new_instance
145
     * @return array
146
     */
147 View Code Duplication
    public function update( $new_instance )
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...
148
    {
149
        if($this->can_update())
150
        {
151
            $old_instance = $this->get_old_instance();
152
            $final_instance = $this->form->update($new_instance, $old_instance);
153
            
154
            \update_option($this->config['slug'],$final_instance);
155
156
            return $this->results_array(
157
                $this->get_errors(),
158
                $final_instance
159
            );
160
        }
161
        return $this->results_array(
162
            array("You don't have permission to manage options on this site")
163
        );
164
    }
165
    
166
    /**
167
     * Ajax callback internally used to reset all component values to their 
168
     * defaults for the given settings page.
169
     * 
170
     * @return type
171
     */
172
    public function reset()
173
    {
174
        if($this->can_update())
175
        {
176
            \delete_option($this->config['slug']);
177
178
            return $this->results_array(
179
                array(),
180
                $this->form->reset()
181
            );
182
        }
183
        return $this->results_array(
184
            array("You don't have permission to manage options on this site")
185
        );
186
    }
187
188
    /**
189
     * Ajax callback internally used to reset all component values to their 
190
     * defaults for the given settings section.
191
     *
192
     * @param string $slug
193
     * @return void
194
     */
195 View Code Duplication
    public function reset_section( $slug ) 
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...
196
    {
197
        if($this->can_update())
198
        {
199
            $old_instance = $this->get_old_instance();
200
            $final_instance = $this->form->reset_components($this->get_section_fields($slug));
201
            
202
            \update_option($this->config['slug'], 
203
                // Array merge is needed in order not to delete fields from other sections
204
                // since the $final_instance only contains the fields that were reset
205
                array_merge($old_instance, $final_instance)
206
            );
207
208
            return $this->results_array(
209
                array(),
210
                $final_instance
211
            );
212
        }
213
        return $this->results_array(
214
            array("You don't have permission to manage options on this site")
215
        );
216
    }
217
    
218
    /**
219
     * Renders Amarkal's credits on the page's footer.
220
     */
221
    public function footer_credits()
222
    {
223
        echo '<span id="footer-thankyou">Created with <a href="https://github.com/askupasoftware/amarkal-settings">amarkal-settings</a>, a module within the <a href="https://github.com/askupasoftware/amarkal">Amarkal Framework</a></span>';
224
    }
225
226
    /**
227
     * Get the component corresponding to the given name
228
     *
229
     * @param [string] $name
0 ignored issues
show
Documentation introduced by
The doc-type [string] could not be parsed: Unknown type name "" 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...
230
     * @throws RuntimeException when the component cannot be found
231
     * @return void
232
     */
233
    public function get_component($name)
234
    {
235
        return $this->form->get_component_list()->get_by_name($name);
236
    }
237
238
    /**
239
     * Get all the fields for the given section
240
     *
241
     * @param string $slug
242
     * @return array
243
     */
244
    private function get_section_fields($slug)
245
    {
246
        $fields = array();
247
        foreach($this->fields->get_all() as $c)
248
        {
249
            if($c->section === $slug)
250
            {
251
                $fields[] = $c;
252
            }
253
        }
254
        return $fields;
255
    }
256
    
257
    /**
258
     * Get all errors from the form instance.
259
     * 
260
     * @return array
261
     */
262
    private function get_errors()
263
    {
264
        $errors = array();
265
        foreach($this->form->get_errors() as $name => $error)
266
        {
267
            $errors[$name] = $error;
268
        }
269
        return $errors;
270
    }
271
    
272
    /**
273
     * Generates a results array to be returned when an Ajax request is made.
274
     * 
275
     * @param array $errors The list of errors
276
     * @param array $values The list of values
277
     * @return array
278
     */
279
    private function results_array( $errors = array(), $values = '' )
280
    {
281
        return array(
282
            'values' => $values,
283
            'errors' => $errors
284
        );
285
    }
286
    
287
    /**
288
     * Check if the current user has the required privileges to update the 
289
     * settings values.
290
     * 
291
     * @return boolean
292
     */
293
    private function can_update()
294
    {
295
        return \current_user_can($this->config['capability']);
296
    }
297
    
298
    /**
299
     * Get the old instance from the database.
300
     * 
301
     * @return array
302
     */
303
    private function get_old_instance()
304
    {
305
        return \get_option($this->config['slug'], array());
306
    }
307
    
308
    /**
309
     * The default config arguments array for a page.
310
     * 
311
     * @return array
312
     */
313
    private function default_args()
314
    {
315
        return array(
316
            'parent_slug'    => '',
317
            'slug'           => '',
318
            'title'          => '',
319
            'subtitle'       => '',
320
            'menu_title'     => '',
321
            'capability'     => 'manage_options',
322
            'footer_html'    => '',
323
            'subfooter_html' => ''
324
        );
325
    }
326
327
    /**
328
     * The default config arguments array for a section.
329
     *
330
     * @return void
331
     */
332
    private function default_section_args()
333
    {
334
        return array(
335
            'slug'           => '',
336
            'title'          => '',
337
            'subtitle'       => ''
338
        );
339
    }
340
}