Completed
Branch barista-prod (a83166)
by
unknown
51:15 queued 41:57
created

JsonConfig::setProperty()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace EventEspresso\core\services\json;
4
5
use DomainException;
6
7
/**
8
 * Class JsonConfig
9
 * Abstract parent DTO class for managing configuration data that needs to be persisted to the database.
10
 * Encodes properties to JSON and saves the data in a WP option using the sanitized class name as a key.
11
 * Intended as a replacement for EE_Config_Base classes that are currently serialized
12
 * and saved in one massive ee-config object that has many downsides.
13
 *
14
 * @package EventEspresso\core\domain\entities\config
15
 * @since   $VID:$
16
 */
17
abstract class JsonConfig
18
{
19
20
    /**
21
     * @var boolean $has_changes
22
     */
23
    private $has_changes = false;
24
25
    /**
26
     * @var string $option_name
27
     */
28
    private $option_name;
29
30
31
    /**
32
     * SettingsConfig constructor.
33
     *
34
     * @param array $defaults
35
     */
36
    public function __construct(array $defaults)
37
    {
38
        $this->setOptionName();
39
        $this->load($defaults);
40
        $this->clearChanges();
41
    }
42
43
44
    /**
45
     * @return array
46
     */
47
    abstract protected function getProperties();
48
49
50
    /**
51
     * converts property name to:
52
     *      camelCase for getters ex: show_expired => showExpired
53
     *      PascalCase for setters ex: show_expired => ShowExpired
54
     *
55
     * @param string $string
56
     * @param false  $camelCase
57
     * @return string|string[]
58
     * @since   $VID:$
59
     */
60
    private function convertCase($string, $camelCase = false)
61
    {
62
        $string = str_replace(' ', '', ucwords(str_replace('_', ' ', $string)));
63
        if ($camelCase) {
64
            $string = lcfirst($string);
65
        }
66
        return $string;
67
    }
68
69
70
    /**
71
     * @param string $property
72
     * @param bool   $getter
73
     * @return string
74
     */
75
    private function createGetterSetter($property, $getter = true)
76
    {
77
        $setterOrGetter = $this->convertCase($property, $getter);
78
        // if not a getter, prepend with "set". ex: Show_expired => setShowExpired
79
        $setterOrGetter = ! $getter ? 'set' . $setterOrGetter : $setterOrGetter;
80
        return $this->isValidMethod($setterOrGetter) ? $setterOrGetter : '';
81
    }
82
83
84
    /**
85
     * @param string $method
86
     * @return bool
87
     * @throws DomainException
88
     */
89
    private function isValidMethod($method)
90
    {
91
        if (method_exists($this, $method)) {
92
            return true;
93
        }
94
        throw new DomainException(
95
            sprintf(
96
                esc_html__('Missing %1$s method on JsonConfig class %2$s.', 'event_espresso'),
97
                $method,
98
                get_class($this)
99
            )
100
        );
101
    }
102
103
104
    /**
105
     * converts class name to option name by changing backslashes to dashes
106
     */
107
    private function setOptionName()
108
    {
109
        $this->option_name = str_replace(['EventEspresso', '\\'], ['ee', '-'], get_class($this));
110
    }
111
112
113
    /**
114
     * retrieves WP option for class, decodes the data, and resigns values to properties
115
     *
116
     * @param array $defaults
117
     */
118
    protected function load(array $defaults)
119
    {
120
        $config = get_option($this->option_name, '{}');
121
        $config = (array) json_decode($config) + $defaults;
122
        foreach ($this->getProperties() as $property => $value) {
123
            if ($property === 'option_name') {
124
                continue;
125
            }
126
            // convert to PascalCase and prepend with "set". ex: show_expired => setShowExpired
127
            $setter = $this->createGetterSetter($property, false);
128
            $value  = array_key_exists($property, $config) ? $config[ $property ] : null;
129
            $this->{$setter}($value);
130
        }
131
    }
132
133
134
    /**
135
     * updates property value and marks changes if property value has changed
136
     *
137
     * @param string $property
138
     * @param mixed  $value
139
     */
140
    protected function setProperty($property, $value)
141
    {
142
        $this->markChanges($this->{$property} === $value);
143
        $this->{$property} = $value;
144
    }
145
146
147
    /**
148
     * will only toggle has_changes to true otherwise keeps existing value (ie: will never toggle to false)
149
     * why? this allows this method to be fed with the result of a conditional
150
     * that compares an incoming value in a setter with it's previously set value.
151
     * ie: if $x = 1 and you call setX(1) then the value has not really changed.
152
     *
153
     * @param bool $changes
154
     * @since   $VID:$
155
     */
156
    protected function markChanges($changes = true)
157
    {
158
        $this->has_changes = filter_var($changes, FILTER_VALIDATE_BOOLEAN) ? true : $this->has_changes;
159
    }
160
161
162
    /**
163
     * resets $has_changes flag to false but does NOT actually reset any data
164
     */
165
    public function clearChanges()
166
    {
167
        $this->has_changes = false;
168
    }
169
170
171
    /**
172
     * flag for marking that changes have been made to property data
173
     *
174
     * @return bool
175
     */
176
    public function hasChanges()
177
    {
178
        return $this->has_changes;
179
    }
180
181
182
    /**
183
     * encodes all property data to JSON and saves it to a WP option
184
     */
185
    public function update()
186
    {
187
        $config_exists = get_option($this->option_name);
188
        if ($config_exists && ! $this->has_changes) {
189
            return;
190
        }
191
        $config = [];
192
        foreach ($this->getProperties() as $property => $value) {
193
            if ($property === 'option_name') {
194
                continue;
195
            }
196
            $getter = $this->createGetterSetter($property);
197
            $config[ $property ] = $this->{$getter}();
198
        }
199
        $config = wp_json_encode($config);
200
        if ($config_exists) {
201
            update_option($this->option_name, $config);
202
        } else {
203
            add_option($this->option_name, $config, '', 'no');
204
        }
205
        $this->clearChanges();
206
    }
207
}
208