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

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