Passed
Pull Request — master (#7)
by Dante
02:11
created

HtmlHelper::metaDescription()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 1
dl 0
loc 11
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
        $otherdata = $data;
120
        foreach (['description', 'author', 'docType', 'project'] as $attribute) {
121
            if (isset($otherdata[$attribute])) {
122
                unset($otherdata[$attribute]);
123
            }
124
        }
125
        if (!empty($otherdata)) {
126
            foreach ($otherdata as $attribute) {
127
                if (!empty($otherdata[$attribute])) {
128
                    $html .= $this->meta([
129
                        'name' => $attribute,
130
                        'content' => $otherdata[$attribute],
131
                    ]);
132
                }
133
            }
134
        }
135
136
        return $html;
137
    }
138
139
    /**
140
     * Return html meta description tag for passed description argument
141
     *
142
     * @param string|null $description The description
143
     * @return string
144
     */
145
    public function metaDescription($description) : string
146
    {
147
        if (empty($description)) {
148
            return '';
149
        }
150
        $html = $this->meta('description', h(strip_tags($description)));
151
        if ($html === null) {
152
            $html = '';
153
        }
154
155
        return $html;
156
    }
157
158
    /**
159
     * Return html meta author tag for passed creator argument
160
     *
161
     * @param string|null $creator The content creator
162
     * @return string
163
     */
164
    public function metaAuthor(?string $creator) : string
165
    {
166
        if (empty($creator)) {
167
            $creator = $this->getMetaString([], 'author', '');
168
            if (empty($creator)) {
169
                return '';
170
            }
171
        }
172
        $html = $this->meta([
173
            'name' => 'author',
174
            'content' => h($creator),
175
        ]);
176
        if ($html === null) {
177
            $html = '';
178
        }
179
180
        return $html;
181
    }
182
183
    /**
184
     * Return html meta css tag for passed doc type
185
     *
186
     * @param string $docType The doc type
187
     * @return string
188
     */
189
    public function metaCss(string $docType) : string
190
    {
191
        if ($docType === 'html5') {
192
            $docType = $this->getMetaString([], 'docType', '');
193
            if (empty($docType)) {
194
                return '';
195
            }
196
        }
197
        $html = $this->meta([
198
            'http-equiv' => 'Content-Style-Type',
199
            'content' => 'text/css',
200
        ]);
201
        if ($html === null) {
202
            $html = '';
203
        }
204
205
        return $html;
206
    }
207
208
    /**
209
     * Return html meta for generator by project name and version passed
210
     *
211
     * @param array $project The project data ('name', 'version')
212
     * @return string
213
     */
214
    public function metaGenerator(array $project) : string
215
    {
216
        if (empty($project['name'])) {
217
            $project = $this->getMetaArray([], 'project', []);
218
            if (empty($project['name'])) {
219
                return '';
220
            }
221
        }
222
        $version = '';
223
        if (!empty($project['version'])) {
224
            $version = $project['version'];
225
        }
226
        $html = $this->meta([
227
            'name' => 'generator',
228
            'content' => trim(sprintf('%s %s', $project['name'], $version)),
229
        ]);
230
        if ($html === null) {
231
            $html = '';
232
        }
233
234
        return $html;
235
    }
236
237
    /**
238
     * Return html meta for opengraph / facebook
239
     * OG fields:
240
     *
241
     *  - og:title
242
     *  - og:type
243
     *  - og:url
244
     *  - og:image
245
     *
246
     * OG optional fields:
247
     *
248
     *  - og:audio
249
     *  - og:description
250
     *  - og:determiner
251
     *  - og:locale
252
     *  - og:locale:alternate
253
     *  - og:site_name
254
     *  - og:video
255
     *
256
     * OG structured fields:
257
     *
258
     *  - og:image:url // identical to og:image
259
     *  - og:image:secure_url
260
     *  - og:image:type
261
     *  - og:image:width
262
     *  - og:image:height
263
     *  - og:image:alt
264
     *  - og:video:url // identical to og:video
265
     *  - og:video:secure_url
266
     *  - og:video:type
267
     *  - og:video:width
268
     *  - og:video:height
269
     *  - og:audio
270
     *  - og:secure_url
271
     *  - og:type
272
     *
273
     * For details @see http://ogp.me
274
     *
275
     * @param array $data The data ('title', 'type', 'image', 'url')
276
     * @return string
277
     */
278
    public function metaOpenGraph(array $data) : string
279
    {
280
        $html = '';
281
        foreach ($data as $attribute => $val) {
282
            $tmp = $this->meta([
283
                'property' => sprintf('og:%s', $attribute),
284
                'content' => $val,
285
            ]);
286
            if ($tmp !== null) {
287
                $html .= $tmp;
288
            }
289
        }
290
291
        return $html;
292
    }
293
294
    /**
295
     * Return html meta for twitter
296
     * twitter fields:
297
     *
298
     *  - twitter:card
299
     *  - twitter:site
300
     *  - twitter:site:id
301
     *  - twitter:creator
302
     *  - twitter:creator:id
303
     *  - twitter:description
304
     *  - twitter:title
305
     *  - twitter:image
306
     *  - twitter:image:alt
307
     *  - twitter:player
308
     *  - twitter:player:width
309
     *  - twitter:player:height
310
     *  - twitter:player:stream
311
     *  - twitter:app:name:iphone
312
     *  - twitter:app:id:iphone
313
     *  - twitter:app:url:iphone
314
     *  - twitter:app:name:ipad
315
     *  - twitter:app:id:ipad
316
     *  - twitter:app:url:ipad
317
     *  - twitter:app:name:googleplay
318
     *  - twitter:app:id:googleplay
319
     *  - twitter:app:url:googleplay
320
     *
321
     * For details @see https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/markup.html
322
     *
323
     * @param array $data The data ('card', 'site', 'creator', 'title', 'description', 'image')
324
     * @return string
325
     */
326
    public function metaTwitter(array $data) : string
327
    {
328
        $html = '';
329
        foreach ($data as $attribute => $val) {
330
            $tmp = $this->meta([
331
                'property' => sprintf('twitter:%s', $attribute),
332
                'content' => $val,
333
            ]);
334
            if ($tmp !== null) {
335
                $html .= $tmp;
336
            }
337
        }
338
339
        return $html;
340
    }
341
342
    /**
343
     * Return meta by data and field
344
     *
345
     * @param array $data The data
346
     * @param string $field The field
347
     * @param string $defaultVal The default val
348
     * @return string
349
     */
350
    public function getMetaString(array $data, string $field, ?string $defaultVal) : string
351
    {
352
        if (isset($data[$field])) {
353
            return $data[$field];
354
        }
355
        if (isset($this->metadata[$field])) {
356
            return $this->metadata[$field];
357
        }
358
359
        return (string)$defaultVal;
360
    }
361
362
    /**
363
     * Return meta by data and field
364
     *
365
     * @param array $data The data
366
     * @param string $field The field
367
     * @param array|null $defaultVal The default val
368
     * @return array
369
     */
370
    public function getMetaArray(array $data, string $field, ?array $defaultVal) : array
371
    {
372
        if (isset($data[$field])) {
373
            return $data[$field];
374
        }
375
        if (isset($this->metadata[$field])) {
376
            return $this->metadata[$field];
377
        }
378
379
        return (array)$defaultVal;
380
    }
381
}
382