Passed
Pull Request — master (#7)
by Dante
01:34
created

HtmlHelper::getMetaArray()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 3
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2018 ChannelWeb Srl, Chialab Srl
5
 *
6
 * This file is part of BEdita: you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
12
 */
13
14
namespace BEdita\WebTools\View\Helper;
15
16
use Cake\Core\Configure;
17
use Cake\Utility\Inflector;
18
use Cake\View\Helper\HtmlHelper as CakeHtmlHelper;
19
use Cake\View\View;
20
21
/**
22
 * Html helper.
23
 * It extends {@see \Cake\View\Helper\HtmlHelper} Cake Html Helper
24
 */
25
class HtmlHelper extends CakeHtmlHelper
26
{
27
28
    /**
29
     * Meta data for helper
30
     */
31
    protected $metadata = [
32
        'description' => '',
33
        'author' => '',
34
        'viewport' => '',
35
        'msapplication-TileColor' => '',
36
        'theme-color' => '',
37
        'docType' => '',
38
        'project' => [
39
            'name' => '',
40
            'version' => '',
41
        ],
42
    ];
43
44
    /**
45
     * Construct the meta data
46
     * Merge data to $this->metadata from configure 'Meta', if set
47
     * Merge data to $this->metadata from $config['meta'], if set
48
     *
49
     * @param \Cake\View\View $View The View this helper is being attached to.
50
     * @param array $config Configuration settings for the helper.
51
     */
52
    public function __construct(View $View, array $config = [])
53
    {
54
        if ($meta = Configure::read('Meta')) {
55
            $this->metadata += $meta;
56
        }
57
        if (isset($config['meta'])) {
58
            $this->metadata = $config['meta'] + $this->metadata;
59
            unset($config['meta']);
60
        }
61
        parent::__construct($View, $config);
62
    }
63
64
    /**
65
     * Title for template pages
66
     * If `_title` view var is set, return it
67
     * Otherwise return controller name (and action name if set)
68
     *
69
     * @return string
70
     */
71
    public function title() : string
72
    {
73
        if (isset($this->getView()->viewVars['_title'])) {
74
            return $this->getView()->viewVars['_title'];
75
        }
76
        $title = Inflector::humanize($this->getView()->request->getParam('controller', ''));
77
        $suffix = Inflector::humanize($this->getView()->request->getParam('action', ''));
78
        if (empty($title)) {
79
            $title = $suffix;
80
        } elseif (!empty($suffix)) {
81
            $title .= sprintf(' - %s', $suffix);
82
        }
83
84
        return $title;
85
    }
86
87
    /**
88
     * Html meta
89
     * Possible meta data:
90
     *
91
     *  - description
92
     *  - author
93
     *  - viewport
94
     *  - msapplication-TileColor
95
     *  - theme-color
96
     *  - docType
97
     *  - project.name
98
     *  - project.version
99
     *
100
     * @param array $data Data for meta: 'description', 'author', 'viewport', 'msapplication-TileColor', 'theme-color', 'docType', 'project' (['name' => '...', 'version' => '...'])
101
     * @return string
102
     * @see HtmlHelper
103
     */
104
    public function metaAll(array $data) : string
105
    {
106
        $html = '';
107
108
        // description
109
        $description = $this->getMetaString($data, 'description', '');
110
        $html .= $this->metaDescription($description);
111
112
        // author
113
        $author = $this->getMetaString($data, 'author', '');
114
        $html .= $this->metaAuthor($author);
115
116
        // viewport, msapplication-TileColor, theme-color
117
        foreach (['viewport', 'msapplication-TileColor', 'theme-color'] as $attribute) {
118
            if (!empty($data[$attribute])) {
119
                $html .= $this->meta([
120
                    'name' => $attribute,
121
                    'content' => $data[$attribute],
122
                ]);
123
            }
124
        }
125
126
        // css
127
        $docType = $this->getMetaString($data, 'docType', 'xhtml-strict');
128
        $html .= $this->metaCss($docType);
129
130
        // generator
131
        $project = $this->getMetaArray($data, 'project', []);
132
        $html .= $this->metaGenerator($project);
133
134
        return $html;
135
    }
136
137
    /**
138
     * Return html meta description tag for passed description argument
139
     *
140
     * @param string|null $description The description
141
     * @return string
142
     */
143
    public function metaDescription($description) : string
144
    {
145
        if (empty($description)) {
146
            return '';
147
        }
148
        $html = $this->meta('description', h(strip_tags($description)));
149
        if ($html === null) {
150
            $html = '';
151
        }
152
153
        return $html;
154
    }
155
156
    /**
157
     * Return html meta author tag for passed creator argument
158
     *
159
     * @param string|null $creator The content creator
160
     * @return string
161
     */
162
    public function metaAuthor(?string $creator) : string
163
    {
164
        if (empty($creator)) {
165
            $creator = $this->getMetaString([], 'author', '');
166
            if (empty($creator)) {
167
                return '';
168
            }
169
        }
170
        $html = $this->meta([
171
            'name' => 'author',
172
            'content' => h($creator),
173
        ]);
174
        if ($html === null) {
175
            $html = '';
176
        }
177
178
        return $html;
179
    }
180
181
    /**
182
     * Return html meta css tag for passed doc type
183
     *
184
     * @param string $docType The doc type
185
     * @return string
186
     */
187
    public function metaCss(string $docType) : string
188
    {
189
        if ($docType === 'html5') {
190
            $docType = $this->getMetaString([], 'docType', '');
191
            if (empty($docType)) {
192
                return '';
193
            }
194
        }
195
        $html = $this->meta([
196
            'http-equiv' => 'Content-Style-Type',
197
            'content' => 'text/css',
198
        ]);
199
        if ($html === null) {
200
            $html = '';
201
        }
202
203
        return $html;
204
    }
205
206
    /**
207
     * Return html meta for generator by project name and version passed
208
     *
209
     * @param array $project The project data ('name', 'version')
210
     * @return string
211
     */
212
    public function metaGenerator(array $project) : string
213
    {
214
        if (empty($project) || empty($project['name'])) {
215
            $project = $this->getMetaArray([], 'project', []);
216
            if (empty($project) || empty($project['name'])) {
217
                return '';
218
            }
219
        }
220
        $version = '';
221
        if (!empty($project['version'])) {
222
            $version = $project['version'];
223
        }
224
        $html = $this->meta([
225
            'name' => 'generator',
226
            'content' => trim(sprintf('%s %s', $project['name'], $version)),
227
        ]);
228
        if ($html === null) {
229
            $html = '';
230
        }
231
232
        return $html;
233
    }
234
235
    /**
236
     * Return html meta for opengraph / facebook
237
     * OG fields:
238
     *
239
     *  - og:title
240
     *  - og:type
241
     *  - og:url
242
     *  - og:image
243
     *
244
     * OG optional fields:
245
     *
246
     *  - og:audio
247
     *  - og:description
248
     *  - og:determiner
249
     *  - og:locale
250
     *  - og:locale:alternate
251
     *  - og:site_name
252
     *  - og:video
253
     *
254
     * OG structured fields:
255
     *
256
     *  - og:image:url // identical to og:image
257
     *  - og:image:secure_url
258
     *  - og:image:type
259
     *  - og:image:width
260
     *  - og:image:height
261
     *  - og:image:alt
262
     *  - og:video:url // identical to og:video
263
     *  - og:video:secure_url
264
     *  - og:video:type
265
     *  - og:video:width
266
     *  - og:video:height
267
     *  - og:audio
268
     *  - og:secure_url
269
     *  - og:type
270
     *
271
     * For details @see http://ogp.me
272
     *
273
     * @param array $data The data ('title', 'type', 'image', 'url')
274
     * @return string
275
     */
276
    public function metaOpenGraph(array $data) : string
277
    {
278
        $html = '';
279
        foreach ($data as $attribute => $val) {
280
            $tmp = $this->meta([
281
                'property' => sprintf('og:%s', $attribute),
282
                'content' => $val,
283
            ]);
284
            if ($tmp !== null) {
285
                $html .= $tmp;
286
            }
287
        }
288
289
        return $html;
290
    }
291
292
    /**
293
     * Return html meta for twitter
294
     * twitter fields:
295
     *
296
     *  - twitter:card
297
     *  - twitter:site
298
     *  - twitter:site:id
299
     *  - twitter:creator
300
     *  - twitter:creator:id
301
     *  - twitter:description
302
     *  - twitter:title
303
     *  - twitter:image
304
     *  - twitter:image:alt
305
     *  - twitter:player
306
     *  - twitter:player:width
307
     *  - twitter:player:height
308
     *  - twitter:player:stream
309
     *  - twitter:app:name:iphone
310
     *  - twitter:app:id:iphone
311
     *  - twitter:app:url:iphone
312
     *  - twitter:app:name:ipad
313
     *  - twitter:app:id:ipad
314
     *  - twitter:app:url:ipad
315
     *  - twitter:app:name:googleplay
316
     *  - twitter:app:id:googleplay
317
     *  - twitter:app:url:googleplay
318
     *
319
     * For details @see https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/markup.html
320
     *
321
     * @param array $data The data ('card', 'site', 'creator', 'title', 'description', 'image')
322
     * @return string
323
     */
324
    public function metaTwitter(array $data) : string
325
    {
326
        $html = '';
327
        foreach ($data as $attribute => $val) {
328
            $tmp = $this->meta([
329
                'property' => sprintf('twitter:%s', $attribute),
330
                'content' => $val,
331
            ]);
332
            if ($tmp !== null) {
333
                $html .= $tmp;
334
            }
335
        }
336
337
        return $html;
338
    }
339
340
    /**
341
     * Return meta by data and field
342
     *
343
     * @param array $data The data
344
     * @param string $field The field
345
     * @param string $defaultVal The default val
346
     * @return string
347
     */
348
    public function getMetaString(array $data, string $field, ?string $defaultVal) : string
349
    {
350
        if (isset($data[$field])) {
351
            return $data[$field];
352
        }
353
        if (isset($this->metadata[$field])) {
354
            return $this->metadata[$field];
355
        }
356
357
        return (string)$defaultVal;
358
    }
359
360
    /**
361
     * Return meta by data and field
362
     *
363
     * @param array $data The data
364
     * @param string $field The field
365
     * @param array|null $defaultVal The default val
366
     * @return array
367
     */
368
    public function getMetaArray(array $data, string $field, ?array $defaultVal) : array
369
    {
370
        if (isset($data[$field])) {
371
            return $data[$field];
372
        }
373
        if (isset($this->metadata[$field])) {
374
            return $this->metadata[$field];
375
        }
376
377
        return (array)$defaultVal;
378
    }
379
}
380