Completed
Push — master ( 131e79...afdc39 )
by Andreas
34:52 queued 12:29
created

midcom_services_metadata::set_request_metadata()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package midcom.services
4
 * @author The Midgard Project, http://www.midgard-project.org
5
 * @copyright The Midgard Project, http://www.midgard-project.org
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
7
 */
8
9
/**
10
 * Metadata service.
11
 *
12
 * This service utilizes MidCOM's metadata system to provide meaningful, auto-generated
13
 * meta and link tags into documents. It is also entry point site builders can use to
14
 * retrieve metadata about current page.
15
 *
16
 * @package midcom.services
17
 */
18
class midcom_services_metadata
19
{
20
    /**
21
     * The metadata currently available. This array is indexed by context id; each
22
     * value consists of a metadata object. The metadata objects are created on-demand.
23
     *
24
     * @var midcom_helper_metadata[]
25
     */
26
    private $_metadata = [];
27
28
    /**
29
     * Class of the current page per each context.
30
     * Typically these are the same as the schema name of the current object's Datamanager schema.
31
     * This can be used for changing site styling based on body class="" etc.
32
     *
33
     * @var Array
34
     */
35
    private $_page_classes = [];
36
37
    /**
38
     * Returns the view metadata of the specified context.
39
     *
40
     * @param int $context_id The context to retrieve the view metadata for, this
41
     *     defaults to the current context.
42
     * @return midcom_helper_metadata
43
     */
44
    public function get_view_metadata($context_id = null)
45
    {
46
        if ($context_id === null) {
47
            $context_id = midcom_core_context::get()->id;
48
        }
49
50
        return $this->_metadata[$context_id] ?? null;
51
    }
52
53
    /**
54
     * Sets the class of the current page for a context
55
     *
56
     * @param string $page_class The class that should be used for the page
57
     */
58 31
    function set_page_class($page_class)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
59
    {
60 31
        $context = midcom_core_context::get();
61
62
        // Append current topic to page class if enabled
63 31
        if (midcom::get()->config->get('page_class_include_component')) {
64 31
            $page_class .= ' ' . str_replace('.', '_', $context->get_key(MIDCOM_CONTEXT_COMPONENT));
65
        }
66
67
        // Append a custom class from topic to page class
68 31
        $topic_class = $context->get_key(MIDCOM_CONTEXT_CONTENTTOPIC)->get_parameter('midcom.services.metadata', 'page_class');
69 31
        if (!empty($topic_class)) {
70
            $page_class .= " {$topic_class}";
71
        }
72
73 31
        $this->_page_classes[$context->id] = trim($page_class);
74 31
    }
75
76
    /**
77
     * Gets the CSS class of the current page of a context
78
     */
79
    public function get_page_class() : string
80
    {
81
        $context = midcom_core_context::get();
82
83
        if (array_key_exists($context->id, $this->_page_classes)) {
84
            return $this->_page_classes[$context->id];
85
        }
86
        return 'default';
87
    }
88
89
    /**
90
     * Get CSS classes for an object. This will include two new CSS classes for the object's class string
91
     * if appropriate:
92
     *
93
     * - unapproved: approvals are enabled for the site but the object is not translated
94
     * - hidden: object is hidden via metadata settings or scheduling
95
     *
96
     * @param midcom_core_dbaobject $object The DBA class instance to get CSS classes for
97
     * @param string $existing_classes Existing CSS classes to append to
98
     */
99 37
    public function get_object_classes($object, $existing_classes = null) : string
100
    {
101 37
        $css_classes = [];
102 37
        if ($existing_classes !== null) {
103 32
            $css_classes[] = $existing_classes;
104
        }
105
106
        // Approval attributes
107 37
        if (   midcom::get()->config->get('metadata_approval')
108 37
            && !$object->metadata->is_approved()) {
109
            $css_classes[] = 'unapproved';
110
        }
111
112
        // Hiding and scheduling attributes
113 37
        if (   (   !midcom::get()->config->get('show_hidden_objects')
114 37
                || midcom::get()->config->get('metadata_scheduling'))
115 37
            && !$object->metadata->is_visible()) {
116
            $css_classes[] = 'hidden';
117
        }
118
119
        // Folder's class
120 37
        if (   $object instanceof midcom_db_topic
121 37
            && $page_class = $object->get_parameter('midcom.services.metadata', 'page_class')) {
122
            $css_classes[] = $page_class;
123
        }
124
125 37
        return implode(' ', $css_classes);
126
    }
127
128
    /**
129
     * Binds view metadata to a DBA content object
130
     *
131
     * @param midcom_core_dbaobject $object The DBA class instance to bind to.
132
     */
133 51
    public function bind_to($object)
134
    {
135 51
        $context = midcom_core_context::get();
136
137 51
        $this->_metadata[$context->id] = midcom_helper_metadata::retrieve($object);
138 51
        if (!$this->_metadata[$context->id]) {
139
            return;
140
        }
141
142
        // Update request metadata if appropriate
143 51
        $request_metadata = $this->get_request_metadata($context);
144 51
        $edited = $this->_metadata[$context->id]->get('revised');
145 51
        if ($edited > $request_metadata['lastmodified']) {
146 24
            $this->set_request_metadata($edited, $request_metadata['permalinkguid']);
0 ignored issues
show
Bug introduced by
It seems like $request_metadata['permalinkguid'] can also be of type false; however, parameter $permalinkguid of midcom_services_metadata::set_request_metadata() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

146
            $this->set_request_metadata($edited, /** @scrutinizer ignore-type */ $request_metadata['permalinkguid']);
Loading history...
147
        }
148 51
    }
149
150
    /**
151
     * Populates appropriate metadata into HTML documents based on metadata information
152
     * available to MidCOM for the request.
153
     */
154
    public function populate_meta_head()
155
    {
156
        // HTML generator information
157
        midcom::get()->head->add_meta_head(['name' => 'generator', 'content' => 'MidCOM']);
158
159
        // If an object has been bound we have more information available
160
        if ($view_metadata = $this->get_view_metadata()) {
161
            foreach (midcom::get()->config->get('metadata_head_elements') as $property => $metatag) {
162
                if ($content = $view_metadata->get($property)) {
163
                    // Handle date fields
164
                    if (in_array($property, ['published', 'created', 'revised', 'approved', 'locked'])) {
165
                        $content = gmdate('Y-m-d', (int) $content);
166
                    }
167
168
                    midcom::get()->head->add_meta_head([
169
                        'name' => $metatag,
170
                        'content' => $content,
171
                    ]);
172
                }
173
            }
174
            // TODO: Add support for tags here
175
176
            if (midcom::get()->config->get('metadata_opengraph')) {
177
                $this->_add_opengraph_metadata($view_metadata);
178
            }
179
        }
180
    }
181
182
    private function _add_opengraph_metadata(midcom_helper_metadata $view_metadata)
183
    {
184
        $opengraph_type = $view_metadata->object->get_parameter('midcom.helper.metadata', 'opengraph_type');
185
        if (   $opengraph_type
186
            && $opengraph_type != 'none') {
187
            $request_metadata = $this->get_request_metadata();
188
189
            midcom::get()->head->add_meta_head([
190
                'property' => 'og:type',
191
                'content' => $opengraph_type,
192
            ]);
193
            midcom::get()->head->add_meta_head([
194
                'property' => 'og:title',
195
                'content' => midcom_core_context::get()->get_key(MIDCOM_CONTEXT_PAGETITLE),
196
            ]);
197
            midcom::get()->head->add_meta_head([
198
                'property' => 'og:url',
199
                'content' => $request_metadata['permalink'],
200
            ]);
201
            $opengraph_image = $view_metadata->object->get_parameter('midcom.helper.metadata', 'opengraph_image');
202
            if (mgd_is_guid($opengraph_image)) {
203
                midcom::get()->head->add_meta_head([
204
                    'property' => 'og:image',
205
                    'content' => midcom_db_attachment::get_url($opengraph_image),
206
                ]);
207
            }
208
            midcom::get()->head->add_meta_head([
209
                'property' => 'og:description',
210
                'content' => $view_metadata->get('description'),
211
            ]);
212
        }
213
    }
214
215
    /**
216
     * Return a list of Open Graph Protocol types
217
     *
218
     * @see http://opengraphprotocol.org/
219
     */
220 99
    public function get_opengraph_types() : array
221
    {
222 99
        if (!midcom::get()->config->get('metadata_opengraph')) {
223 99
            return [];
224
        }
225
226
        return [
227
            'none' => 'opengraph type select',
228
            'activity' => 'opengraph activity activity',
229
            'sport' => 'opengraph activity sport',
230
            'bar' => 'opengraph business bar',
231
            'company' => 'opengraph business company',
232
            'hotel' => 'opengraph business hotel',
233
            'restaurant' => 'opengraph business restaurant',
234
            'cause' => 'opengraph group cause',
235
            'sports_league' => 'opengraph group sports_league',
236
            'sports_team' => 'opengraph group sports_team',
237
            'band' => 'opengraph organization band',
238
            'government' => 'opengraph organization government',
239
            'non_profit' => 'opengraph organization non_profit',
240
            'school' => 'opengraph organization school',
241
            'university' => 'opengraph organization university',
242
            'actor' => 'opengraph person actor',
243
            'athlete' => 'opengraph person athlete',
244
            'author' => 'opengraph person author',
245
            'director' => 'opengraph person director',
246
            'musician' => 'opengraph person musician',
247
            'politician' => 'opengraph person politician',
248
            'public_figure' => 'opengraph person public_figure',
249
            'city' => 'opengraph place city',
250
            'country' => 'opengraph place country',
251
            'landmark' => 'opengraph place landmark',
252
            'state_province' => 'opengraph place state_province',
253
            'album' => 'opengraph product album',
254
            'book' => 'opengraph product book',
255
            'drink' => 'opengraph product drink',
256
            'food' => 'opengraph product food',
257
            'game' => 'opengraph product game',
258
            'movie' => 'opengraph product movie',
259
            'product' => 'opengraph product product',
260
            'song' => 'opengraph product song',
261
            'tv_show' => 'opengraph product tv_show',
262
            'article' => 'opengraph website article',
263
            'blog' => 'opengraph website blog',
264
            'website' => 'opengraph website website',
265
        ];
266
    }
267
268
    /**
269
     * Get the default Open Graph Protocol type for an object
270
     */
271 99
    public function get_opengraph_type_default() : string
272
    {
273 99
        if (!midcom::get()->config->get('metadata_opengraph')) {
274 99
            return '';
275
        }
276
277
        $context = midcom_core_context::get();
278
        if (empty($this->_metadata[$context->id])) {
279
            return '';
280
        }
281
        $object = $this->_metadata[$context->id]->object;
282
283
        $component = $context->get_key(MIDCOM_CONTEXT_COMPONENT);
284
        if (!$component) {
285
            return '';
286
        }
287
288
        $interface = midcom::get()->componentloader->get_interface_class($component);
289
        if (!method_exists($interface, 'get_opengraph_default')) {
290
            return '';
291
        }
292
293
        return $interface->get_opengraph_default($object);
294
    }
295
296
    /**
297
     * Set the currently known and required Request Metadata: The last modified timestamp and the permalink GUID.
298
     *
299
     * You may set either of the arguments to null to enforce default usage (based on NAP).
300
     *
301
     * @param int $lastmodified The date of last modification of this request.
302
     * @param string $permalinkguid The GUID used to create a permalink for this request.
303
     */
304 65
    public function set_request_metadata(int $lastmodified, $permalinkguid)
305
    {
306 65
        $context = midcom_core_context::get();
307
308 65
        $context->set_key(MIDCOM_CONTEXT_LASTMODIFIED, $lastmodified);
309 65
        $context->set_key(MIDCOM_CONTEXT_PERMALINKGUID, $permalinkguid);
310 65
    }
311
312
    /**
313
     * Get the currently known and required Request Metadata: The last modified timestamp and the permalink GUID.
314
     *
315
     * @param midcom_core_context $context The context from which the request metadata should be retrieved. Omit
316
     *     to use the current context.
317
     * @return Array An array with the two keys 'lastmodified' and 'permalinkguid' containing the
318
     *     values set with the setter pendant. For ease of use, there is also a key 'permalink'
319
     *     which contains a ready-made permalink.
320
     */
321 51
    public function get_request_metadata(midcom_core_context $context = null) : array
322
    {
323 51
        if ($context === null) {
324
            $context = midcom_core_context::get();
325
        }
326
        return [
327 51
            'lastmodified' => $context->get_key(MIDCOM_CONTEXT_LASTMODIFIED),
328 51
            'permalinkguid' => $context->get_key(MIDCOM_CONTEXT_PERMALINKGUID),
329 51
            'permalink' => midcom::get()->permalinks->create_permalink($context->get_key(MIDCOM_CONTEXT_PERMALINKGUID)),
0 ignored issues
show
Bug introduced by
It seems like $context->get_key(MIDCOM_CONTEXT_PERMALINKGUID) can also be of type false; however, parameter $guid of midcom_services_permalinks::create_permalink() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

329
            'permalink' => midcom::get()->permalinks->create_permalink(/** @scrutinizer ignore-type */ $context->get_key(MIDCOM_CONTEXT_PERMALINKGUID)),
Loading history...
330
        ];
331
    }
332
}
333