Completed
Push — master ( c4aa45...6dfe1b )
by Bjørn
03:12
created

OptionsTrait::checkOptions()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 7.9062

Importance

Changes 0
Metric Value
cc 4
eloc 8
nc 3
nop 0
dl 0
loc 12
ccs 3
cts 8
cp 0.375
crap 7.9062
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace WebPConvert\Convert\BaseConverters\BaseTraits;
4
5
use WebPConvert\Convert\Exceptions\ConversionFailed\ConversionSkippedException;
6
use WebPConvert\Convert\Exceptions\ConversionFailed\InvalidInput\InvalidOptionTypeException;
7
8
/**
9
 * Trait for handling options
10
 *
11
 * This trait is currently only used in the AbstractConverter class. It has been extracted into a
12
 * trait in order to bundle the methods concerning options.
13
 *
14
 * @package    WebPConvert
15
 * @author     Bjørn Rosell <[email protected]>
16
 * @since      Class available since Release 2.0.0
17
 */
18
trait OptionsTrait
19
{
20
21
    /** @var array  Provided conversion options */
22
    public $providedOptions;
23
24
    /** @var array  Calculated conversion options (merge of default options and provided options)*/
25
    protected $options;
26
27
    abstract protected function getMimeTypeOfSource();
28
29
    /** @var array  Definitions of general options (the options that are available on all converters) */
30
    protected static $optionDefinitionsBasic = [
31
        ['quality', 'number|string', 'auto'],    // PS: Default is altered to 85 for PNG in ::getDefaultOptions()
32
        ['max-quality', 'number', 85],
33
        ['default-quality', 'number', 75],       // PS: Default is altered to 85 for PNG in ::getDefaultOptions()
34
        ['metadata', 'string', 'none'],
35
        ['lossless', 'boolean|string', false],  // PS: Default is altered to "auto" for PNG in ::getDefaultOptions()
36
        ['skip', 'boolean', false],
37
    ];
38
39
    /**
40
     * Set "provided options" (options provided by the user when calling convert().
41
     *
42
     * This also calculates the protected options array, by merging in the default options.
43
     * Converters shall access the $this->options array to get options.
44
     *
45
     * @param   array $providedOptions (optional)
46
     * @return  void
47
     */
48 33
    public function setProvidedOptions($providedOptions = [])
49
    {
50 33
        $this->providedOptions = $providedOptions;
51
52 33
        if (isset($this->providedOptions['png'])) {
53
            if ($this->getMimeTypeOfSource() == 'image/png') {
54
                $this->providedOptions = array_merge($this->providedOptions, $this->providedOptions['png']);
55
//                $this->logLn(print_r($this->providedOptions, true));
56
            }
57
        }
58
59 33
        if (isset($this->providedOptions['jpeg'])) {
60
            if ($this->getMimeTypeOfSource() == 'image/jpeg') {
61
                $this->providedOptions = array_merge($this->providedOptions, $this->providedOptions['jpeg']);
62
            }
63
        }
64
        // -  Merge $defaultOptions into provided options
65 33
        $this->options = array_merge($this->getDefaultOptions(), $this->providedOptions);
66 33
    }
67
68
    /**
69
     * Get definitions of general options (those available for all converters)
70
     *
71
     * To get only the extra definitions for a specific converter, call
72
     * ::getOptionDefinitionsExtra(). To get both general and extra, merged together, call ::getOptionDefinitions().
73
     *
74
     * @return array  A numeric array of definitions of general options for the converter.
75
     *                Each definition is a numeric array with three items: [option id, type, default value]
76
     */
77
    public function getGeneralOptionDefinitions()
78
    {
79
        return self::$optionDefinitionsBasic;
80
    }
81
82
    /**
83
     * Get definitions of extra options unique for the actual converter.
84
     *
85
     * @return array  A numeric array of definitions of all options for the converter.
86
     *                Each definition is a numeric array with three items: [option id, type, default value]
87
     */
88
    abstract protected function getOptionDefinitionsExtra();
89
90
    /**
91
     * Get option definitions for the converter (includes both general options and the extra options for the converter)
92
     *
93
     * To get only the general options definitions (those available for all converters), call
94
     * ::getGeneralOptionDefinitions(). To get only the extra definitions for a specific converter, call
95
     * ::getOptionDefinitionsExtra().
96
     *
97
     * @return array  A numeric array of definitions of all options for the converter.
98
     *                Each definition is a numeric array with three items: [option id, type, default value]
99
     */
100 33
    public function getOptionDefinitions()
101
    {
102 33
        return array_merge(self::$optionDefinitionsBasic, $this->getOptionDefinitionsExtra());
103
    }
104
105
    /**
106
     * Get default options for the converter.
107
     *
108
     * Note that the defaults depends on the mime type of the source. For example, the default value for quality
109
     * is "auto" for jpegs, and 85 for pngs.
110
     *
111
     * @return array  An associative array of option defaults: ['metadata' => 'none', ...]
112
     */
113 33
    public function getDefaultOptions()
114
    {
115 33
        $defaults = [];
116 33
        foreach ($this->getOptionDefinitions() as list($name, $type, $default)) {
117 33
            $defaults[$name] = $default;
118
        }
119 33
        if ($this->getMimeTypeOfSource() == 'image/png') {
120 17
            $defaults['lossless'] = 'auto';
121 17
            $defaults['quality'] = 85;
122 17
            $defaults['default-quality'] = 85;
123
        }
124 33
        return $defaults;
125
    }
126
127
    /**
128
     *  Check option types generally (against their definitions).
129
     *
130
     *  @throws InvalidOptionTypeException  if type is invalid
131
     *  @return void
132
     */
133 13
    private function checkOptionTypesGenerally()
134
    {
135 13
        foreach ($this->getOptionDefinitions() as $def) {
136 13
            list($optionName, $optionType) = $def;
137 13
            if (isset($this->providedOptions[$optionName])) {
138 10
                $actualType = gettype($this->providedOptions[$optionName]);
139 10
                if ($actualType != $optionType) {
140 6
                    $optionType = str_replace('number', 'integer|double', $optionType);
141 6
                    if (!in_array($actualType, explode('|', $optionType))) {
142
                        throw new InvalidOptionTypeException(
143
                            'The provided ' . $optionName . ' option is not a ' . $optionType .
144 13
                                ' (it is a ' . $actualType . ')'
145
                        );
146
                    }
147
                }
148
            }
149
        }
150 13
    }
151
152
    /**
153
     *  Check quality option
154
     *
155
     *  @throws InvalidOptionTypeException  if value is out of range
156
     *  @return void
157
     */
158 13
    private function checkQualityOption()
159
    {
160 13
        if (!isset($this->providedOptions['quality'])) {
161 13
            return;
162
        }
163 1
        $optionValue = $this->providedOptions['quality'];
164 1
        if (gettype($optionValue) == 'string') {
165 1
            if ($optionValue != 'auto') {
166
                throw new InvalidOptionTypeException(
167
                    'Quality option must be either "auto" or a number between 0-100. ' .
168 1
                    'A string, "' . $optionValue . '" was given'
169
                );
170
            }
171
        } else {
172
            if (($optionValue < 0) || ($optionValue > 100)) {
173
                throw new InvalidOptionTypeException(
174
                    'Quality option must be either "auto" or a number between 0-100. ' .
175
                        'The number you provided (' . strval($optionValue) . ') is out of range.'
176
                );
177
            }
178
        }
179 1
    }
180
181
    /**
182
     *  Check lossless option
183
     *
184
     *  @throws InvalidOptionTypeException  if value is out of range
185
     *  @return void
186
     */
187 13
    private function checkLosslessOption()
188
    {
189 13
        if (!isset($this->providedOptions['lossless'])) {
190 8
            return;
191
        }
192 6
        $optionValue = $this->providedOptions['lossless'];
193 6
        if ((gettype($optionValue) == 'string') && ($optionValue != 'auto')) {
194
            throw new InvalidOptionTypeException(
195
                'Lossless option must be true, false or "auto". It was set to: "' . $optionValue . '"'
196
            );
197
        }
198 6
    }
199
200
    /**
201
     *  Check option types.
202
     *
203
     *  @throws InvalidOptionTypeException  if an option value have wrong type or is out of range
204
     *  @return void
205
     */
206 13
    private function checkOptionTypes()
207
    {
208 13
        $this->checkOptionTypesGenerally();
209 13
        $this->checkQualityOption();
210 13
        $this->checkLosslessOption();
211 13
    }
212
213
    /**
214
     *  Check options.
215
     *
216
     *  @throws InvalidOptionTypeException  if an option value have wrong type or is out of range
217
     *  @throws ConversionSkippedException  if 'skip' option is set to true
218
     *  @return void
219
     */
220 13
    protected function checkOptions()
221
    {
222 13
        $this->checkOptionTypes();
223
224 13
        if ($this->options['skip']) {
225
            if (($this->getMimeTypeOfSource() == 'image/png') && isset($this->options['png']['skip'])) {
226
                throw new ConversionSkippedException(
227
                    'skipped conversion (configured to do so for PNG)'
228
                );
229
            } else {
230
                throw new ConversionSkippedException(
231
                    'skipped conversion (configured to do so)'
232
                );
233
            }
234
        }
235 13
    }
236
}
237