Completed
Push — master ( 8820dc...f61110 )
by Andrew
01:53
created

code/SEO_Icons_SiteConfig_DataExtension.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
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(
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(
42
        // Favicon
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
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
        // @todo Figure out how to pass messages to the CMS tooltip
213
        // regenerate manifest
214
        if ($this->generateAndroidManifest()) {
0 ignored issues
show
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
215
            // SilverStripe success message
0 ignored issues
show
Unused Code Comprehensibility introduced by
44% 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...
216
//            Session::set('Message', array(
217
//                'MessageType' => 'Success',
218
//                'Message' => 'Android manifest successfully generated.'
219
//            ));
220
        } else {
0 ignored issues
show
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
221
            // SilverStripe failure message
0 ignored issues
show
Unused Code Comprehensibility introduced by
44% 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...
222
//            Session::set('Message', array(
223
//                'MessageType' => 'Error',
224
//                'Message' => 'Android manifest could not be generated, please check permissions on `\manifest.json`'
225
//            ));
226
        }
227
228
    }
229
230
231
    /* Custom Methods
232
    ------------------------------------------------------------------------------*/
233
234
    //// Fetch functions
235
236
    /**
237
     * Fetches the pinicon title.
238
     *
239
     * @return bool|string
240
     */
241
    public function fetchPiniconTitle()
242
    {
243
244
        if ($this->owner->PiniconTitle) {
245
            // return pinicon title
246
            return $this->owner->PiniconTitle;
247
        } else {
248
            // default
249
            return false;
250
        }
251
252
    }
253
254
    /**
255
     * Fetches the Android pinicon theme color.
256
     *
257
     * @return string|false
258
     */
259
    public function fetchAndroidPiniconThemeColor()
260
    {
261
262
        if ($this->owner->AndroidPiniconThemeColor) {
263
            return '#' . $this->owner->AndroidPiniconThemeColor;
264
        } else {
265
            return false;
266
        }
267
268
    }
269
270
    /**
271
     * Fetches the Windows pinicon background color.
272
     *
273
     * @return string|false
274
     */
275
    public function fetchWindowsPiniconBackgroundColor()
276
    {
277
278
        if ($this->owner->WindowsPiniconBackgroundColor) {
279
            return '#' . $this->owner->WindowsPiniconBackgroundColor;
280
        } else {
281
            return false;
282
        }
283
284
    }
285
286
    //// Generate functions
287
288
    /**
289
     * Generates the android manifest
290
     *
291
     * @todo check this is working 100%
292
     *
293
     * @return bool
294
     */
295
    public function generateAndroidManifest()
296
    {
297
298
        //// Android Pinicon Manifest
299
300
        $pinicon = $this->owner->AndroidPinicon();
301
302
        if ($pinicon->exists()) {
303
304
            //
305
            $manifest = new stdClass();
306
307
            //
308
            $manifest->name = $this->owner->PiniconTitle;
309
//			$manifest->start_url = null; @todo Maybe implement
310
//			$manifest->display = null; @todo Maybe implement
311
//			$manifest->orientation = null; @todo Maybe implement
312
            $manifest->icons = array();
313
314
            // 0.75x density icon
315
            array_push($manifest->icons, array(
316
                'src' => $pinicon->Fill(36, 36)->getAbsoluteURL(),
317
                'sizes' => '36x36',
318
                'type' => 'image/png',
319
                'density' => 0.75
320
            ));
321
322
            // 1x density icon
323
            array_push($manifest->icons, array(
324
                'src' => $pinicon->Fill(48, 48)->getAbsoluteURL(),
325
                'sizes' => '48x48',
326
                'type' => 'image/png',
327
                'density' => 1
328
            ));
329
330
            // 1.5x density icon
331
            array_push($manifest->icons, array(
332
                'src' => $pinicon->Fill(72, 72)->getAbsoluteURL(),
333
                'sizes' => '72x72',
334
                'type' => 'image/png',
335
                'density' => 1.5
336
            ));
337
338
            // 2x density icon
339
            array_push($manifest->icons, array(
340
                'src' => $pinicon->Fill(96, 96)->getAbsoluteURL(),
341
                'sizes' => '96x96',
342
                'type' => 'image/png',
343
                'density' => 2
344
            ));
345
346
            // 3x density icon
347
            array_push($manifest->icons, array(
348
                'src' => $pinicon->Fill(144, 144)->getAbsoluteURL(),
349
                'sizes' => '144x144',
350
                'type' => 'image/png',
351
                'density' => 3
352
            ));
353
354
            // 4x density icon
355
            array_push($manifest->icons, array(
356
                'src' => $pinicon->Fill(192, 192)->getAbsoluteURL(),
357
                'sizes' => '192x192',
358
                'type' => 'image/png',
359
                'density' => 4
360
            ));
361
362
            // create file
363
            $bytes = file_put_contents(Director::baseFolder() . '/manifest.json', json_encode($manifest));
364
365
            //
366
            if ($bytes !== false) {
367
                // success
368
                return true;
369
            }
370
371
        }
372
373
        // default return
374
        return false;
375
376
    }
377
378
}
379