Completed
Push — master ( 27f11f...9e269b )
by Andrew
01:57
created

fetchAndroidPiniconThemeColor()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 2
eloc 5
nc 2
nop 0
1
<?php
2
3
/**
4
 * @todo Description
5
 *
6
 * I called them Pinicons & Tabicons in keeping with the absolutely pointless name: Favicons.
7
 *
8
 * @package silverstripe-seo
9
 * @subpackage icons
10
 * @author Andrew Gerber <[email protected]>
11
 * @version 1.0.0
12
 *
13
 */
14
class SEO_Icons_SiteConfig_DataExtension extends DataExtension
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
15
{
16
17
18
    /* Static Variables
19
    ------------------------------------------------------------------------------*/
20
21
    //
22
    private static $SEOIconsUpload = 'SEO/SiteConfig/Icons/';
23
24
    //
25
    const APPLE_ICON_DEFAULT_BACKGROUND = '000000';
26
27
28
    /* Overload Model
29
    ------------------------------------------------------------------------------*/
30
31
    private static $db = array(
0 ignored issues
show
Unused Code introduced by
The property $db is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
32
        // Pinned Icon Title
33
        'PiniconTitle' => 'Varchar(128)',
34
        // Android Pinned Icon
35
        'AndroidPiniconThemeColor' => 'Varchar(6)',
36
        // MS Tile
37
        'WindowsPiniconBackgroundColor' => 'Varchar(6)',
38
        // Safari Pinned Tab
39
//		'SafariTabiconThemeColor' => 'Varchar(6)', // @todo maybe implement
40
    );
41
    private static $has_one = array(
0 ignored issues
show
Unused Code introduced by
The property $has_one is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
42
        // Favicon
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
43
//		'HTML4Favicon' => 'Image', // @todo maybe implement
44
        'HTML5Favicon' => 'Image',
45
        // Apple Pinned Icon
46
        'IOSPinicon' => 'Image',
47
        // Android Pinned Icon
48
        'AndroidPinicon' => 'Image',
49
        // Windows Pinned Icon
50
        'WindowsPinicon' => 'Image',
51
        // Safari Pinned Tab
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
52
//		'SafariTabiconDefault' => 'Image', // @todo maybe implement
53
//		'SafariTabiconWide' => 'Image', // @todo maybe implement
54
//		'SafariTabiconLarge' => 'Image', // @todo maybe implement
55
    );
56
57
58
    /* Overload Methods
59
    ------------------------------------------------------------------------------*/
60
61
    /**
62
     * Adds tabs & fields to the CMS.
63
     *
64
     * @param FieldList $fields
65
     */
66
    public function updateCMSFields(FieldList $fields)
67
    {
68
69
        //// Favicons Tab
70
71
        $tab = 'Root.Metadata.Favicons';
72
73
        //// Favicon
74
75
        $fields->addFieldsToTab($tab, array(
76
            LabelField::create('FaviconDescription', 'Favicons are `favourite icons` used by browsers in a number of ways whenever an icon is necessary e.g. tabs, history, bookmarks, dashboards.<br />@ <a href="https://en.wikipedia.org/wiki/Favicon" target="_blank">Favicon - Wikipedia, the free encyclopedia</a>')
77
                ->addExtraClass('information')
78
        ));
79
80
        //// HTML4 Favicon
81
82
        // check favicon.ico & set status
83
        $icoStatus = ReadonlyField::create('HTML4FaviconStatus', 'Favicon ICO<pre>type: ico</pre><pre>size: (multiple)<br />16x16 & 32x32 & 64x64 px</pre>', 'favicon.ico error');
84
        if (Director::fileExists('favicon.ico')) {
85
            $icoStatus
86
                ->setValue('favicon.ico found')
87
                ->addExtraClass('success favicon');
88
        } else {
89
            $icoStatus
90
                ->setValue('favicon.ico not found')
91
                ->addExtraClass('error');
92
        }
93
94
        // header & fields
95
        $fields->addFieldsToTab($tab, array(
96
            HeaderField::create('HTML4FaviconHeader', 'HTML4 <span class="aka">( favicon.ico )</span>'),
97
            LabelField::create('HTML4FaviconDescription', 'It is recommended you simply have a `favicon.ico` file in the webroot.')
98
                ->addExtraClass('information'),
99
            $icoStatus
100
        ));
101
102
        //// HTML5 Favicon
103
104
        // header & fields
105
        $fields->addFieldsToTab($tab, array(
106
            HeaderField::create('HTML5FaviconHeader', 'HTML5 <span class="aka">( favicon.png )</span>'),
107
            LabelField::create('HTML5FaviconDescription', '@todo Description')
108
                ->addExtraClass('information'),
109
            UploadField::create('HTML5Favicon', 'Favicon PNG<pre>type: png</pre><pre>size: 192x192 px</pre>')
110
                ->setAllowedExtensions(array('png'))
111
                ->setFolderName(self::$SEOIconsUpload)
112
        ));
113
114
        //// Pinned Icons Tab
115
116
        $tab = 'Root.Metadata.PinnedIcons';
117
118
        //// Pinned Icons Information
119
120
        $fields->addFieldsToTab($tab, array(
121
            LabelField::create('PiniconDescription', 'Pinned icons are OS-specific desktop shortcuts to pages on your website, they allow you to configure additional theming options to make pages appear more `native` / `web-app-y` within the OS.<br />Given they are OS-specific, they (obviously!) have a different format for each one :(')
122
                ->addExtraClass('information')
123
        ));
124
125
        //// Pinned Icon Title
126
127
        // CMS fields
128
        $fields->addFieldsToTab($tab, array(
129
            // header
130
            HeaderField::create('PiniconTitleHeader', 'Pinned Icon Title <span class="aka">( a.k.a. App Name )</span>'),
131
            // description
132
            LabelField::create('PiniconTitleDescription', 'When adding a link to the home screen, the user can choose a caption. By default, this is the bookmarked page title, which is usually fine. However, iOS and Windows 8 let you override this default value.')
133
                ->addExtraClass('information'),
134
            TextField::create('PiniconTitle', 'Application Title')
135
                ->setAttribute('placeholder', 'default: page title')
136
        ));
137
138
        //// iOS Pinned Icon
139
140
        // CMS fields
141
        $fields->addFieldsToTab($tab, array(
142
            // header
143
            HeaderField::create('IOSPiniconHeader', 'iOS Pinned Icon <span class="aka">( a.k.a. Touch Icons, Web Clips )</span>'),
144
            // information
145
            LabelField::create('IOSPiniconDescription', 'iPhone and iPad users can pin your web site on their home screen. The link looks like a native app.<br />@ <a href="https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html" target="_blank">Configuring Web Applications - iOS Developer Library</a>')
146
                ->addExtraClass('information'),
147
            // icon
148
            UploadField::create('IOSPinicon', 'iOS Icon<pre>type: png</pre><pre>size: 192x192 px</pre>')
149
                ->setAllowedExtensions(array('png'))
150
                ->setFolderName(self::$SEOIconsUpload)
151
                ->setDescription('iOS will fill the transparent regions with black by default, so put your own background in!')
152
        ));
153
154
        //// Android Pinned Icon
155
156
        // CMS fields
157
        $fields->addFieldsToTab($tab, array(
158
            // header
159
            HeaderField::create('AndroidPiniconHeader', 'Android Pinned Icon <span class="aka">( a.k.a. Android Chrome Icons, Launcher Icons )</span>'),
160
            // information
161
            LabelField::create('AndroidPiniconDescription', 'Add to Homescreen is a also a feature of Android Chrome. Your visitors can mix their natives apps and web bookmarks.<br />@ <a href="https://developer.chrome.com/multidevice/android/installtohomescreen" target="_blank">Add to Homescreen - Google Chrome</a>')
162
                ->addExtraClass('information'),
163
            // icon
164
            UploadField::create('AndroidPinicon', 'Android Icon<pre>type: png</pre><pre>size: 192x192 px</pre>')
165
                ->setAllowedExtensions(array('png'))
166
                ->setFolderName(self::$SEOIconsUpload),
167
            // background
168
            TextField::create('AndroidPiniconThemeColor', 'Theme Color<pre>type: hex triplet</pre>')
169
                ->setAttribute('placeholder', 'none')
170
                ->setAttribute('size', 6)
171
                ->setMaxLength(6)
172
                ->setDescription('Starting with Android Lollipop, you can customize the color of the task bar in the switcher.')
173
        ));
174
175
        //// Windows Pinned Icon
176
177
        // CMS fields
178
        $fields->addFieldsToTab($tab, array(
179
            // header
180
            HeaderField::create('WindowsShortcutHeader', 'Windows Pinned Icon <span class="aka">( a.k.a. Windows 8 / Metro Tiles )</span>'),
181
            // information
182
            LabelField::create('WindowsShortcutDescription', 'Windows 8 users can pin your web site on their desktop. Your site appears as a tile, just like a native Windows 8 app.<br />@ <a href="https://msdn.microsoft.com/en-us/library/dn455106" target="_blank">Creating custom tiles for IE11 websites (Windows)</a>')
183
                ->addExtraClass('information'),
184
            // icon
185
            UploadField::create('WindowsPinicon', 'Windows Icon<pre>type: png</pre><pre>size: 192x192 px</pre>')
186
                ->setAllowedExtensions(array('png'))
187
                ->setFolderName(self::$SEOIconsUpload),
188
            // background
189
            TextField::create('WindowsPiniconBackgroundColor', 'Background ( Tile ) Color<pre>type: hex triplet</pre>')
190
                ->setAttribute('placeholder', 'none')
191
                ->setAttribute('size', 6)
192
                ->setMaxLength(6)
193
        ));
194
195
        // @todo Safari Pinned Tab ~ maybe ??
196
197
    }
198
199
    /**
200
     * Generates the Android manifest.json file.
201
     *
202
     * @todo Information about permissions
203
     *
204
     * @return void
205
     */
206
    public function onAfterWrite()
207
    {
208
209
        // parent
210
        parent::onAfterWrite();
211
212
        // regenerate manifest
213
        if ($this->generateAndroidManifest()) {
214
            // SilverStripe success message
215
            $this->setMessage('Success', 'Android manifest successfully generated.');
0 ignored issues
show
Bug introduced by
The method setMessage() does not seem to exist on object<SEO_Icons_SiteConfig_DataExtension>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
216
        } else {
217
            // SilverStripe failure message
218
            $this->setMessage('Error', 'Android manifest could not be generated, please check permissions on `\manifest.json`');
0 ignored issues
show
Bug introduced by
The method setMessage() does not seem to exist on object<SEO_Icons_SiteConfig_DataExtension>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
219
        }
220
221
    }
222
223
224
    /* Custom Methods
225
    ------------------------------------------------------------------------------*/
226
227
    //// Fetch functions
228
229
    /**
230
     * Fetches the pinicon title.
231
     *
232
     * @return bool|string
233
     */
234
    public function fetchPiniconTitle()
235
    {
236
237
        if ($this->owner->PiniconTitle) {
238
            // return pinicon title
239
            return $this->owner->PiniconTitle;
240
        } else {
241
            // default
242
            return false;
243
        }
244
245
    }
246
247
    /**
248
     * Fetches the Android pinicon theme color.
249
     *
250
     * @return bool|string
251
     */
252
    public function fetchAndroidPiniconThemeColor()
253
    {
254
255
        if ($this->owner->AndroidPiniconThemeColor) {
256
            return '#' . $this->owner->AndroidPiniconThemeColor;
257
        } else {
258
            return false;
259
        }
260
261
    }
262
263
    /**
264
     * Fetches the Windows pinicon background color.
265
     *
266
     * @return bool|string
267
     */
268
    public function fetchWindowsPiniconBackgroundColor()
269
    {
270
271
        if ($this->owner->WindowsPiniconBackgroundColor) {
272
            return '#' . $this->owner->WindowsPiniconBackgroundColor;
273
        } else {
274
            return false;
275
        }
276
277
    }
278
279
    //// Generate functions
280
281
    /**
282
     * Generates the android manifest
283
     *
284
     * @todo check this is working 100%
285
     *
286
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
287
     */
288
    public function generateAndroidManifest()
0 ignored issues
show
Coding Style introduced by
generateAndroidManifest uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
289
    {
290
291
        //// Android Pinicon Manifest
292
293
        $pinicon = $this->owner->AndroidPinicon();
294
295
        if ($pinicon->exists()) {
296
297
            //
298
            $manifest = new stdClass();
299
300
            //
301
            $manifest->name = $this->owner->PiniconTitle;
302
//			$manifest->start_url = null; @todo Maybe implement
303
//			$manifest->display = null; @todo Maybe implement
304
//			$manifest->orientation = null; @todo Maybe implement
305
            $manifest->icons = array();
306
307
            // 0.75x density icon
308
            array_push($manifest->icons, array(
309
                'src' => $pinicon->Fill(36, 36)->getAbsoluteURL(),
310
                'sizes' => '36x36',
311
                'type' => 'image/png',
312
                'density' => 0.75
313
            ));
314
315
            // 1x density icon
316
            array_push($manifest->icons, array(
317
                'src' => $pinicon->Fill(48, 48)->getAbsoluteURL(),
318
                'sizes' => '48x48',
319
                'type' => 'image/png',
320
                'density' => 1
321
            ));
322
323
            // 1.5x density icon
324
            array_push($manifest->icons, array(
325
                'src' => $pinicon->Fill(72, 72)->getAbsoluteURL(),
326
                'sizes' => '72x72',
327
                'type' => 'image/png',
328
                'density' => 1.5
329
            ));
330
331
            // 2x density icon
332
            array_push($manifest->icons, array(
333
                'src' => $pinicon->Fill(96, 96)->getAbsoluteURL(),
334
                'sizes' => '96x96',
335
                'type' => 'image/png',
336
                'density' => 2
337
            ));
338
339
            // 3x density icon
340
            array_push($manifest->icons, array(
341
                'src' => $pinicon->Fill(144, 144)->getAbsoluteURL(),
342
                'sizes' => '144x144',
343
                'type' => 'image/png',
344
                'density' => 3
345
            ));
346
347
            // 4x density icon
348
            array_push($manifest->icons, array(
349
                'src' => $pinicon->Fill(192, 192)->getAbsoluteURL(),
350
                'sizes' => '192x192',
351
                'type' => 'image/png',
352
                'density' => 4
353
            ));
354
355
            // create file
356
            $bytes = file_put_contents($_SERVER['DOCUMENT_ROOT'] . '/manifest.json', json_encode($manifest));
357
358
            //
359
            if ($bytes !== false) {
0 ignored issues
show
Coding Style introduced by
The if-else statement can be simplified to return $bytes !== false;.
Loading history...
360
                // success
361
                return true;
362
            } else {
363
                // failure
364
                return false;
365
            }
366
367
        }
368
369
    }
370
371
}
372