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

code/SEO_Icons_SiteConfig_DataExtension.php (3 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
        // regenerate manifest
213
        if ($this->generateAndroidManifest()) {
214
            // SilverStripe success message
215
            $this->setMessage('Success', 'Android manifest successfully generated.');
0 ignored issues
show
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
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
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()
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) {
360
                // success
361
                return true;
362
            } else {
363
                // failure
364
                return false;
365
            }
366
367
        }
368
369
    }
370
371
}
372