Passed
Push — master ( 19e3b7...6548a2 )
by Andreas
23:32
created

midcom_services_metadata::get_object_classes()   B

Complexity

Conditions 9
Paths 16

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 9.648

Importance

Changes 0
Metric Value
cc 9
eloc 14
nc 16
nop 2
dl 0
loc 27
ccs 12
cts 15
cp 0.8
crap 9.648
rs 8.0555
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
     */
43
    public function get_view_metadata(int $context_id = null) : ?midcom_helper_metadata
44
    {
45
        if ($context_id === null) {
46
            $context_id = midcom_core_context::get()->id;
47
        }
48
49
        return $this->_metadata[$context_id] ?? null;
50
    }
51
52
    /**
53
     * Sets the class of the current page for a context
54
     */
55 31
    public function set_page_class(string $page_class)
56
    {
57 31
        $context = midcom_core_context::get();
58
59
        // Append current topic to page class if enabled
60 31
        if (midcom::get()->config->get('page_class_include_component')) {
61 31
            $page_class .= ' ' . str_replace('.', '_', $context->get_key(MIDCOM_CONTEXT_COMPONENT));
62
        }
63
64
        // Append a custom class from topic to page class
65 31
        $topic_class = $context->get_key(MIDCOM_CONTEXT_CONTENTTOPIC)->get_parameter('midcom.services.metadata', 'page_class');
66 31
        if (!empty($topic_class)) {
67
            $page_class .= " {$topic_class}";
68
        }
69
70 31
        $this->_page_classes[$context->id] = trim($page_class);
71
    }
72
73
    /**
74
     * Gets the CSS class of the current page of a context
75
     */
76
    public function get_page_class() : string
77
    {
78
        $context = midcom_core_context::get();
79
80
        if (array_key_exists($context->id, $this->_page_classes)) {
81
            return $this->_page_classes[$context->id];
82
        }
83
        return 'default';
84
    }
85
86
    /**
87
     * Get CSS classes for an object. This will include two new CSS classes for the object's class string
88
     * if appropriate:
89
     *
90
     * - unapproved: approvals are enabled for the site but the object is not translated
91
     * - hidden: object is hidden via metadata settings or scheduling
92
     */
93 37
    public function get_object_classes(midcom_core_dbaobject $object, string $existing_classes = null) : string
94
    {
95 37
        $css_classes = [];
96 37
        if ($existing_classes !== null) {
97 32
            $css_classes[] = $existing_classes;
98
        }
99
100
        // Approval attributes
101 37
        if (   midcom::get()->config->get('metadata_approval')
102 37
            && !$object->metadata->is_approved()) {
103
            $css_classes[] = 'unapproved';
104
        }
105
106
        // Hiding and scheduling attributes
107 37
        if (   (   !midcom::get()->config->get('show_hidden_objects')
108 37
                || midcom::get()->config->get('metadata_scheduling'))
109 37
            && !$object->metadata->is_visible()) {
110
            $css_classes[] = 'hidden';
111
        }
112
113
        // Folder's class
114 37
        if (   $object instanceof midcom_db_topic
115 37
            && $page_class = $object->get_parameter('midcom.services.metadata', 'page_class')) {
116
            $css_classes[] = $page_class;
117
        }
118
119 37
        return implode(' ', $css_classes);
120
    }
121
122
    /**
123
     * Binds view metadata to a DBA content object
124
     */
125 51
    public function bind_to(midcom_core_dbaobject $object)
126
    {
127 51
        $context = midcom_core_context::get();
128
129 51
        $this->_metadata[$context->id] = midcom_helper_metadata::retrieve($object);
130 51
        if (!$this->_metadata[$context->id]) {
131
            return;
132
        }
133
134
        // Update request metadata if appropriate
135 51
        $request_metadata = $this->get_request_metadata($context);
136 51
        $edited = $this->_metadata[$context->id]->get('revised');
137 51
        if ($edited > $request_metadata['lastmodified']) {
138 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 null|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

138
            $this->set_request_metadata($edited, /** @scrutinizer ignore-type */ $request_metadata['permalinkguid']);
Loading history...
Bug introduced by
It seems like $edited can also be of type null and string; however, parameter $lastmodified of midcom_services_metadata::set_request_metadata() does only seem to accept integer, 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

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

318
            'permalink' => midcom::get()->permalinks->create_permalink(/** @scrutinizer ignore-type */ $context->get_key(MIDCOM_CONTEXT_PERMALINKGUID)),
Loading history...
319 51
        ];
320
    }
321
}
322