Completed
Push — master ( 9e269b...615cc3 )
by Andrew
02:27
created

code/SEO_Icons_SiteConfig_DataExtension.php (2 issues)

Severity

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
            Session::set('Message', array(
0 ignored issues
show
array('MessageType' => '...ccessfully generated.') is of type array<string,string,{"Me...g","Message":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
216
                'MessageType' => 'Success',
217
                'Message' => 'Android manifest successfully generated.'
218
            ));
219
        } else {
220
            // SilverStripe failure message
221
            Session::set('Message', array(
0 ignored issues
show
array('MessageType' => '... on `\\manifest.json`') is of type array<string,string,{"Me...g","Message":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

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