Completed
Push — master ( a4fc5a...37fa07 )
by Matthias
02:29
created

AppConfiguration   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 558
Duplicated Lines 5.91 %

Coupling/Cohesion

Components 2
Dependencies 1

Test Coverage

Coverage 93.94%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 55
c 1
b 0
f 0
lcom 2
cbo 1
dl 33
loc 558
ccs 155
cts 165
cp 0.9394
rs 6.8

31 Methods

Rating   Name   Duplication   Size   Complexity  
A getManifestUrl() 0 8 2
A setManifestUrl() 0 5 1
A getBackgroundColor() 0 4 1
A setBackgroundColor() 0 5 1
A getDescription() 0 4 1
A setDescription() 0 5 1
A getDirection() 0 4 1
A setDirection() 16 16 2
A getDisplay() 0 4 1
A setDisplay() 17 17 2
A getIcons() 0 4 1
A addIcon() 0 5 1
A getLanguage() 0 4 1
A setLanguage() 0 5 1
A getName() 0 4 1
A setName() 0 5 1
A getOrientation() 0 4 1
A setOrientation() 0 21 2
A getScope() 0 4 1
A setScope() 0 5 1
A getScreenshots() 0 4 1
A addScreenshot() 0 5 1
A getShortName() 0 4 1
A setShortName() 0 5 1
A getStartUrl() 0 4 1
A setStartUrl() 0 5 1
A getThemeColor() 0 4 1
A setThemeColor() 0 5 1
A fromManifestFile() 0 4 1
F fromManifest() 0 63 16
B imageFromData() 0 23 6

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like AppConfiguration often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AppConfiguration, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the fusonic/webapp package.
5
 *
6
 * (c) Fusonic GmbH <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Fusonic\WebApp;
13
14
use Fusonic\WebApp\Generators\ManifestGenerator;
15
use Fusonic\WebApp\Generators\TagGenerator;
16
use Fusonic\WebApp\Objects\Image;
17
18
/**
19
 * Contains all data of a web application to create different assets and/or tags.
20
 *
21
 * @package Fusonic\WebApp
22
 *
23
 * @see ManifestGenerator
24
 * @see TagGenerator
25
 */
26
final class AppConfiguration
27
{
28
    const DIRECTION_LEFT_TO_RIGHT = "ltr";
29
    const DIRECTION_RIGHT_TO_LEFT = "rtl";
30
    const DIRECTION_AUTO = "auto";
31
32
    const DISPLAY_FULLSCREEN = "fullscreen";
33
    const DISPLAY_STANDALONE = "standalone";
34
    const DISPLAY_MINIMAL_UI = "minimal-ui";
35
    const DISPLAY_BROWSER = "browser";
36
37
    const ORIENTATION_ANY = "any";
38
    const ORIENTATION_NATURAL = "natural";
39
    const ORIENTATION_LANDSCAPE = "landscape";
40
    const ORIENTATION_LANDSCAPE_PRIMARY = "landscape-primary";
41
    const ORIENTATION_LANDSCAPE_SECONDARY = "landscape-secondary";
42
    const ORIENTATION_PORTRAIT = "portrait";
43
    const ORIENTATION_PORTRAIT_PRIMARY = "portrait-primary";
44
    const ORIENTATION_PORTRAIT_SECONDARY = "portrait-secondary";
45
46
    const PLATFORM_ANDROID = "android";
47
    const PLATFORM_IOS = "ios";
48
    const PLATFORM_WEB = "web";
49
50
    private $backgroundColor;
51
    private $description;
52
    private $direction;
53
    private $display;
54
    private $icons = [ ];
55
    private $language;
56
    private $name;
57
    private $orientation;
58
    private $scope;
59
    private $screenshots = [ ];
60
    private $shortName;
61
    private $startUrl;
62
    private $themeColor;
63
64
    private $manifestUrl;
65
66
    /**
67
     * Returns the manifest URL.
68
     *
69
     * @return  string
70
     */
71
    public function getManifestUrl()
72
    {
73
        if ($this->manifestUrl === null) {
74
            throw new \LogicException("Manifest URL cannot be null.");
75
        }
76
77
        return $this->manifestUrl;
78
    }
79
80
    /**
81
     * Sets the manifest URL. You MUST set one for proper deployment.
82
     *
83
     * @param   string              $url
84
     *
85
     * @return  AppConfiguration
86
     */
87
    public function setManifestUrl($url)
88
    {
89
        $this->manifestUrl = $url;
90
        return $this;
91
    }
92
93
    /**
94
     * Returns the expected background color for the web application.
95
     *
96
     * @return  string|null
97
     */
98 2
    public function getBackgroundColor()
99
    {
100 2
        return $this->backgroundColor;
101
    }
102
103
    /**
104
     * Sets the expected background color for the web application. Will also be used by Chrome 47 and later to
105
     * auto-generate a splash screen.
106
     *
107
     * <p>
108
     * This value repeats what is already available in the application stylesheet, but can be used by browsers to draw
109
     * the background color of a web application when the manifest is available before the style sheet has loaded.
110
     *
111
     * <p>
112
     * This creates a smooth transition between launching the web application and loading the application's content.
113
     *
114
     * @param   string              $backgroundColor
115
     *
116
     * @return  AppConfiguration
117
     *
118
     * @see https://www.w3.org/TR/appmanifest/#background_color-member
119
     */
120 2
    public function setBackgroundColor($backgroundColor)
121
    {
122 2
        $this->backgroundColor = $backgroundColor;
123 2
        return $this;
124
    }
125
126
    /**
127
     * Returns the general description of what the web application does.
128
     *
129
     * @return  string|null
130
     */
131 2
    public function getDescription()
132
    {
133 2
        return $this->description;
134
    }
135
136
    /**
137
     * Sets a general description of what the web application does.
138
     *
139
     * @param   string              $description
140
     *
141
     * @return  AppConfiguration
142
     *
143
     * @see https://www.w3.org/TR/appmanifest/#description-member
144
     */
145 2
    public function setDescription($description)
146
    {
147 2
        $this->description = $description;
148 2
        return $this;
149
    }
150
151
    /**
152
     * Returns the primary text direction for the {@link $name}, {@link $shortName}, and {@link $description} members.
153
     *
154
     * @return  string|null
155
     */
156 1
    public function getDirection()
157
    {
158 1
        return $this->direction;
159
    }
160
161
    /**
162
     * Sets the primary text direction for the {@link $name}, {@link $shortName}, and {@link $description} members.
163
     *
164
     * @param   string              $direction          One of AppConfiguration::DIRECTION_* constants.
165
     *
166
     * @return  AppConfiguration
167
     *
168
     * @see https://www.w3.org/TR/appmanifest/#dir-member
169
     */
170 2 View Code Duplication
    public function setDirection($direction)
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...
171
    {
172 2
        if (!in_array(
173 2
            $direction,
174
            [
175 2
                self::DIRECTION_LEFT_TO_RIGHT,
176 2
                self::DIRECTION_RIGHT_TO_LEFT,
177
                self::DIRECTION_AUTO
178 2
            ]
179 2
        )) {
180
            throw new \InvalidArgumentException("Use one of AppConfiguration::DIRECTION_* constants.");
181
        }
182
183 2
        $this->direction = $direction;
184 2
        return $this;
185
    }
186
187
    /**
188
     * Returns the preferred display mode.
189
     *
190
     * @return  string|null
191
     */
192 2
    public function getDisplay()
193
    {
194 2
        return $this->display;
195
    }
196
197
    /**
198
     * Sets the preferred display mode.
199
     *
200
     * @param   string              $display            One of AppConfiguration::DISPLAY_* constants.
201
     *
202
     * @return  AppConfiguration
203
     *
204
     * @see https://www.w3.org/TR/appmanifest/#display-member
205
     */
206 2 View Code Duplication
    public function setDisplay($display)
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...
207
    {
208 2
        if (!in_array(
209 2
            $display,
210
            [
211 2
                self::DISPLAY_FULLSCREEN,
212 2
                self::DISPLAY_MINIMAL_UI,
213 2
                self::DISPLAY_STANDALONE,
214
                self::DISPLAY_BROWSER
215 2
            ]
216 2
        )) {
217
            throw new \InvalidArgumentException("Use one of AppConfiguration::DISPLAY_* constants.");
218
        }
219
220 2
        $this->display = $display;
221 2
        return $this;
222
    }
223
224
    /**
225
     * Returns an array of all application icons.
226
     *
227
     * @return  Image[]
228
     */
229 2
    public function getIcons()
230
    {
231 2
        return $this->icons;
232
    }
233
234
    /**
235
     * Adds an application icon.
236
     *
237
     * @param   Image               $icon
238
     *
239
     * @return  AppConfiguration
240
     *
241
     * @see https://www.w3.org/TR/appmanifest/#icons-member
242
     */
243 2
    public function addIcon(Image $icon)
244
    {
245 2
        $this->icons[] = $icon;
246 2
        return $this;
247
    }
248
249
    /**
250
     * Returns the application's language.
251
     *
252
     * @return  string|null
253
     */
254 2
    public function getLanguage()
255
    {
256 2
        return $this->language;
257
    }
258
259
    /**
260
     * Sets the application's language. Must be a RFC5646 compliant string.
261
     *
262
     * @param   string              $language
263
     *
264
     * @return  AppConfiguration
265
     *
266
     * @see https://www.w3.org/TR/appmanifest/#lang-member
267
     */
268 2
    public function setLanguage($language)
269
    {
270 2
        $this->language = $language;
271 2
        return $this;
272
    }
273
274
    /**
275
     * Returns the application's name.
276
     *
277
     * @return  string|null
278
     */
279 2
    public function getName()
280
    {
281 2
        return $this->name;
282
    }
283
284
    /**
285
     * Sets the application's name.
286
     *
287
     * @param   string              $name
288
     *
289
     * @return  AppConfiguration
290
     *
291
     * @see https://www.w3.org/TR/appmanifest/#name-member
292
     */
293 2
    public function setName($name)
294
    {
295 2
        $this->name = $name;
296 2
        return $this;
297
    }
298
299
    /**
300
     * Returns the default device orientation.
301
     *
302
     * @return  string|null
303
     */
304 2
    public function getOrientation()
305
    {
306 2
        return $this->orientation;
307
    }
308
309
    /**
310
     * Sets the default device orientation..
311
     *
312
     * @param   string              $orientation        One of AppConfiguration::ORIENTATION_* constants.
313
     *
314
     * @return  AppConfiguration
315
     *
316
     * @see https://www.w3.org/TR/appmanifest/#orientation-member
317
     */
318 2
    public function setOrientation($orientation)
319
    {
320 2
        if (!in_array(
321 2
            $orientation,
322
            [
323 2
                self::ORIENTATION_ANY,
324 2
                self::ORIENTATION_NATURAL,
325 2
                self::ORIENTATION_LANDSCAPE,
326 2
                self::ORIENTATION_LANDSCAPE_PRIMARY,
327 2
                self::ORIENTATION_LANDSCAPE_SECONDARY,
328 2
                self::ORIENTATION_PORTRAIT,
329 2
                self::ORIENTATION_PORTRAIT_PRIMARY,
330 2
                self::ORIENTATION_PORTRAIT_SECONDARY,
331
            ]
332 2
        )) {
333
            throw new \InvalidArgumentException("Use one of AppConfiguration::ORIENTATION_* constants.");
334
        }
335
336 2
        $this->orientation = $orientation;
337 2
        return $this;
338
    }
339
340
    /**
341
     * Returns the application's navigation scope.
342
     *
343
     * @return  string|null
344
     */
345 2
    public function getScope()
346
    {
347 2
        return $this->scope;
348
    }
349
350
    /**
351
     * Sets the application's navigation scope.
352
     *
353
     * <p>
354
     * This basically restricts what web pages can be viewed while the manifest is applied. If the user navigates the
355
     * application outside the scope, it returns to being a normal web page.
356
     *
357
     * @param   string              $scope
358
     *
359
     * @return  AppConfiguration
360
     *
361
     * @see https://www.w3.org/TR/appmanifest/#scope-member
362
     */
363 2
    public function setScope($scope)
364
    {
365 2
        $this->scope = $scope;
366 2
        return $this;
367
    }
368
369
    /**
370
     * Returns an array of all application screenshots.
371
     *
372
     * @return  Image[]
373
     */
374 2
    public function getScreenshots()
375
    {
376 2
        return $this->screenshots;
377
    }
378
379
    /**
380
     * Adds an application screenshot.
381
     *
382
     * @param   Image               $screenshot
383
     *
384
     * @return  AppConfiguration
385
     *
386
     * @see https://www.w3.org/TR/appmanifest/#screenshots-member
387
     */
388 2
    public function addScreenshot(Image $screenshot)
389
    {
390 2
        $this->screenshots[] = $screenshot;
391 2
        return $this;
392
    }
393
394
    /**
395
     * Returns the application's short name.
396
     *
397
     * @return  string|null
398
     */
399 2
    public function getShortName()
400
    {
401 2
        return $this->shortName;
402
    }
403
404
    /**
405
     * Sets the application's short name.
406
     *
407
     * @param   string              $shortName
408
     *
409
     * @return  AppConfiguration
410
     *
411
     * @see https://www.w3.org/TR/appmanifest/#short_name-member
412
     */
413 2
    public function setShortName($shortName)
414
    {
415 2
        $this->shortName = $shortName;
416 2
        return $this;
417
    }
418
419
    /**
420
     * Returns the application's start URL.
421
     *
422
     * @return  string|null
423
     */
424 2
    public function getStartUrl()
425
    {
426 2
        return $this->startUrl;
427
    }
428
429
    /**
430
     * Sets the application's start URL.
431
     *
432
     * @param   string              $startUrl
433
     *
434
     * @return  AppConfiguration
435
     *
436
     * @see https://www.w3.org/TR/appmanifest/#start_url-member
437
     */
438 2
    public function setStartUrl($startUrl)
439
    {
440 2
        $this->startUrl = $startUrl;
441 2
        return $this;
442
    }
443
444
    /**
445
     * Returns the theme color.
446
     *
447
     * @return  string|null
448
     */
449 2
    public function getThemeColor()
450
    {
451 2
        return $this->themeColor;
452
    }
453
454
    /**
455
     * Sets the theme color. Will be used by Android's task switcher, for example.
456
     *
457
     * @param   string              $color
458
     *
459
     * @return  AppConfiguration
460
     *
461
     * @see https://www.w3.org/TR/appmanifest/#theme_color-member
462
     */
463 2
    public function setThemeColor($color)
464
    {
465 2
        $this->themeColor = $color;
466 2
        return $this;
467
    }
468
469
    /**
470
     * Creates an instance of the {@link AppConfiguration} class based on the values in the provided manifest file. Use
471
     * the {@link fromManifest} method to use a JSON string as source.
472
     *
473
     * @param   string              $path               Path to a file containing an application manifest compatible
474
     *                                                  with the Web App Manifest specification.
475
     *
476
     * @return  AppConfiguration
477
     *
478
     * @see https://www.w3.org/TR/appmanifest/
479
     */
480 1
    public static function fromManifestFile($path)
481
    {
482 1
        return self::fromManifest(file_get_contents($path));
483
    }
484
485
    /**
486
     * Creates an instance of the {@link AppConfiguration} class based on the values in the provided JSON string. Use
487
     * the {@link fromManifestFile} method to use a file as source.
488
     *
489
     * @param   string              $json               A JSON string that is compatible with the Web App Manifest
490
     *                                                  specification.
491
     *
492
     * @return  AppConfiguration
493
     *
494
     * @see https://www.w3.org/TR/appmanifest/
495
     */
496 2
    public static function fromManifest($json)
497
    {
498 2
        $app = new AppConfiguration();
499 2
        $data = json_decode($json, true);
500
501 2
        if (isset($data["background_color"])) {
502 2
            $app->setBackgroundColor($data["background_color"]);
503 2
        }
504
505 2
        if (isset($data["description"])) {
506 2
            $app->setDescription($data["description"]);
507 2
        }
508
509 2
        if (isset($data["dir"])) {
510 2
            $app->setDirection($data["dir"]);
511 2
        }
512
513 2
        if (isset($data["display"])) {
514 2
            $app->setDisplay($data["display"]);
515 2
        }
516
517 2
        if (isset($data["icons"])) {
518 2
            foreach ($data["icons"] as $icon) {
519 2
                $app->addIcon(self::imageFromData($icon));
520 2
            }
521 2
        }
522
523 2
        if (isset($data["lang"])) {
524 2
            $app->setLanguage($data["lang"]);
525 2
        }
526
527 2
        if (isset($data["name"])) {
528 2
            $app->setName($data["name"]);
529 2
        }
530
531 2
        if (isset($data["orientation"])) {
532 2
            $app->setOrientation($data["orientation"]);
533 2
        }
534
535 2
        if (isset($data["scope"])) {
536 2
            $app->setScope($data["scope"]);
537 2
        }
538
539 2
        if (isset($data["screenshots"])) {
540 2
            foreach ($data["screenshots"] as $screenshot) {
541 2
                $app->addScreenshot(self::imageFromData($screenshot));
542 2
            }
543 2
        }
544
545 2
        if (isset($data["short_name"])) {
546 2
            $app->setShortName($data["short_name"]);
547 2
        }
548
549 2
        if (isset($data["start_url"])) {
550 2
            $app->setStartUrl($data["start_url"]);
551 2
        }
552
553 2
        if (isset($data["theme_color"])) {
554 2
            $app->setThemeColor($data["theme_color"]);
555 2
        }
556
557 2
        return $app;
558
    }
559
560 2
    private static function imageFromData(array $data)
561
    {
562 2
        $image = new Image();
563
564 2
        if (isset($data["src"])) {
565 2
            $image->setSrc($data["src"]);
566 2
        }
567
568 2
        if (isset($data["type"])) {
569 2
            $image->setType($data["type"]);
570 2
        }
571
572 2
        if (isset($data["sizes"])) {
573 2
            $sizes = [];
574 2
            if (preg_match_all("/(\d+)x(\d+)/", $data["sizes"], $sizes)) {
575 2
                for ($i = 0; $i < count($sizes[0]); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
576 2
                    $image->addSize($sizes[1][$i], $sizes[2][$i]);
577 2
                }
578 2
            }
579 2
        }
580
581 2
        return $image;
582
    }
583
}
584