Completed
Pull Request — master (#7)
by Dante
03:40
created

HtmlHelper::metaOpenGraph()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 14
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\Hash;
18
use Cake\Utility\Inflector;
19
use Cake\View\Helper\HtmlHelper as CakeHtmlHelper;
20
use Cake\View\View;
21
22
/**
23
 * Html helper.
24
 * It extends {@see \Cake\View\Helper\HtmlHelper} Cake Html Helper
25
 */
26
class HtmlHelper extends CakeHtmlHelper
27
{
28
29
    /**
30
     * Meta data for helper
31
     */
32
    protected $metadata = [
33
        'description' => '',
34
        'author' => '',
35
        'docType' => '',
36
        'project' => [
37
            'name' => '',
38
            'version' => '',
39
        ],
40
    ];
41
42
    /**
43
     * Initialize the meta data
44
     * Merge data to $this->metadata from configure 'Meta', if set
45
     * Merge data to $this->metadata from $config['meta'], if set
46
     *
47
     * @param array $config Configuration settings for the helper.
48
     */
49
    public function initialize(array $config)
50
    {
51
        parent::initialize($config);
52
        if ($meta = Configure::read('Meta')) {
53
            $this->metadata = $meta + $this->metadata;
54
        }
55
        if (isset($config['meta'])) {
56
            $this->metadata = $config['meta'] + $this->metadata;
57
        }
58
    }
59
60
    /**
61
     * Title for template pages
62
     * If `_title` view var is set, return it
63
     * Otherwise return controller name (and action name if set)
64
     *
65
     * @return string
66
     */
67
    public function title() : string
68
    {
69
        if (isset($this->getView()->viewVars['_title'])) {
70
            return $this->getView()->viewVars['_title'];
71
        }
72
        $title = Inflector::humanize($this->getView()->request->getParam('controller', ''));
73
        $suffix = Inflector::humanize($this->getView()->request->getParam('action', ''));
74
        if (empty($title)) {
75
            $title = $suffix;
76
        } elseif (!empty($suffix)) {
77
            $title .= sprintf(' - %s', $suffix);
78
        }
79
80
        return $title;
81
    }
82
83
    /**
84
     * Html meta
85
     * Possible meta data:
86
     *
87
     *  - description
88
     *  - author
89
     *  - docType
90
     *  - project.name
91
     *  - project.version
92
     *
93
     * @param array $data Data for meta: 'description', 'author', 'docType', 'project' (['name' => '...', 'version' => '...'], ...)
94
     * @return string
95
     * @see HtmlHelper
96
     */
97
    public function metaAll(array $data) : string
98
    {
99
        $html = '';
100
101
        // description
102
        $description = (string)$this->getMeta($data, 'description', '');
103
        $html .= $this->metaDescription($description);
104
105
        // author
106
        $author = (string)$this->getMeta($data, 'author', '');
107
        $html .= $this->metaAuthor($author);
108
109
        // css
110
        $docType = (string)$this->getMeta($data, 'docType', 'xhtml-strict');
111
        $html .= $this->metaCss($docType);
112
113
        // generator
114
        $project = (array)$this->getMeta($data, 'project', []);
115
        $html .= $this->metaGenerator($project);
116
117
        // other data
118
        $keys = ['description', 'author', 'docType', 'project'];
119
        $otherdata = array_diff_key($data, array_flip($keys));
120
        if (empty($otherdata)) {
121
            return $html;
122
        }
123
        foreach ($otherdata as $attribute) {
124
            if (!empty($otherdata[$attribute])) {
125
                $html .= $this->meta([
126
                    'name' => $attribute,
127
                    'content' => $otherdata[$attribute],
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(?string $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 = (string)$this->getMeta([], '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 = (string)$this->getMeta([], '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 = (array)$this->getMeta([], '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 array|string|null $defaultVal The default val
344
     * @return array|string
345
     */
346
    public function getMeta(array $data, string $field, $defaultVal = null)
347
    {
348
        $meta = $data + $this->metadata;
349
350
        return Hash::get($meta, $field, $defaultVal);
0 ignored issues
show
Bug Best Practice introduced by
The expression return Cake\Utility\Hash...a, $field, $defaultVal) also could return the type ArrayAccess which is incompatible with the documented return type array|string.
Loading history...
351
    }
352
}
353