Completed
Pull Request — 2.x (#328)
by
unknown
01:30
created

SeoExtension::renderAttributes()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
c 0
b 0
f 0
rs 9.8666
cc 3
nc 3
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\SeoBundle\Twig\Extension;
15
16
use Sonata\SeoBundle\Seo\AttributeBag;
17
use Sonata\SeoBundle\Seo\SeoPageAttributesInterface;
18
use Sonata\SeoBundle\Seo\SeoPageInterface;
19
use Twig\Environment;
20
use Twig\Error\Error;
21
use Twig\Extension\AbstractExtension;
22
use Twig\TwigFunction;
23
24
class SeoExtension extends AbstractExtension
25
{
26
    /**
27
     * @var SeoPageInterface
28
     */
29
    protected $page;
30
31
    /**
32
     * @var string
33
     */
34
    protected $encoding;
35
36
    /**
37
     * @param SeoPageInterface|SeoPageAttributesInterface $page
38
     * @param string                                      $encoding
39
     */
40
    public function __construct(SeoPageInterface $page, $encoding)
41
    {
42
        $this->page = $page;
43
        $this->encoding = $encoding;
44
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49
    public function getFunctions()
50
    {
51
        return [
52
            new TwigFunction('sonata_seo_title', [$this, 'getTitle'], ['is_safe' => ['html']]),
53
            new TwigFunction('sonata_seo_metadatas', [$this, 'getMetadatas'], ['is_safe' => ['html']]),
54
            new TwigFunction('sonata_seo_link_canonical', [$this, 'getLinkCanonical'], ['is_safe' => ['html']]),
55
            new TwigFunction('sonata_seo_lang_alternates', [$this, 'getLangAlternates'], ['is_safe' => ['html']]),
56
            new TwigFunction('sonata_seo_oembed_links', [$this, 'getOembedLinks'], ['is_safe' => ['html']]),
57
            new TwigFunction('sonata_seo_html_attributes', [$this, 'getHtmlAttributes'], ['needs_environment' => true, 'is_safe' => ['html']]),
58
            new TwigFunction('sonata_seo_head_attributes', [$this, 'getHeadAttributes'], ['needs_environment' => true, 'is_safe' => ['html']]),
59
            new TwigFunction('sonata_seo_body_attributes', [$this, 'getBodyAttributes'], ['needs_environment' => true, 'is_safe' => ['html']]),
60
        ];
61
    }
62
63
    /**
64
     * {@inheritdoc}
65
     */
66
    public function getName()
67
    {
68
        return 'sonata_seo';
69
    }
70
71
    /**
72
     * NEXT_MAJOR: remove this method.
73
     *
74
     * @deprecated since 2.0, to be removed in 3.0
75
     */
76
    public function renderTitle()
77
    {
78
        @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
79
            'The '.__METHOD__.' method is deprecated since 2.0, to be removed in 3.0. '.
80
            'Use '.__NAMESPACE__.'::getTitle() instead.',
81
            E_USER_DEPRECATED
82
        );
83
84
        echo $this->getTitle();
85
    }
86
87
    /**
88
     * @return string
89
     */
90
    public function getTitle()
91
    {
92
        return sprintf('<title>%s</title>', strip_tags($this->page->getTitle()));
93
    }
94
95
    /**
96
     * NEXT_MAJOR: remove this method.
97
     *
98
     * @deprecated since 2.0, to be removed in 3.0
99
     */
100
    public function renderMetadatas()
101
    {
102
        @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
103
            'The '.__METHOD__.' method is deprecated since 2.0, to be removed in 3.0. '.
104
            'Use '.__NAMESPACE__.'::getMetadatas() instead.',
105
            E_USER_DEPRECATED
106
        );
107
108
        echo $this->getMetadatas();
109
    }
110
111
    /**
112
     * @return string
113
     */
114
    public function getMetadatas()
115
    {
116
        $html = '';
117
        foreach ($this->page->getMetas() as $type => $metas) {
118
            foreach ((array) $metas as $name => $meta) {
119
                list($content, $extras) = $meta;
0 ignored issues
show
Unused Code introduced by
The assignment to $extras is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
120
121
                if (!empty($content)) {
122
                    $html .= sprintf("<meta %s=\"%s\" content=\"%s\" />\n",
123
                        $type,
124
                        $this->normalize($name),
125
                        $this->normalize($content)
126
                    );
127
                } else {
128
                    $html .= sprintf("<meta %s=\"%s\" />\n",
129
                        $type,
130
                        $this->normalize($name)
131
                    );
132
                }
133
            }
134
        }
135
136
        return $html;
137
    }
138
139
    /**
140
     * NEXT_MAJOR: remove this method.
141
     *
142
     * @deprecated since 2.0, to be removed in 3.0
143
     */
144
    public function renderHtmlAttributes()
145
    {
146
        @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
147
            'The '.__METHOD__.' method is deprecated since 2.0, to be removed in 3.0. '.
148
            'Use '.__NAMESPACE__.'::getHtmlAttributes() instead.',
149
            E_USER_DEPRECATED
150
        );
151
152
        echo $this->getHtmlAttributes();
153
    }
154
155
    public function getHtmlAttributes(Environment $environment = null): string
156
    {
157
        if ($this->page instanceof SeoPageAttributesInterface) {
158
            $attributes = $this->page->htmlAttributes();
159
        } else {
160
            $attributes = new AttributeBag($this->page->getHtmlAttributes());
0 ignored issues
show
Deprecated Code introduced by
The method Sonata\SeoBundle\Seo\Seo...ce::getHtmlAttributes() has been deprecated with message: use htmlAttributes()->all() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
161
        }
162
163
        return $this->renderAttributes($attributes, $environment);
164
    }
165
166
    /**
167
     * NEXT_MAJOR: remove this method.
168
     *
169
     * @deprecated since 2.0, to be removed in 3.0
170
     */
171
    public function renderHeadAttributes()
172
    {
173
        @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
174
            'The '.__METHOD__.' method is deprecated since 2.0, to be removed in 3.0. '.
175
            'Use '.__NAMESPACE__.'::getHeadAttributes() instead.',
176
            E_USER_DEPRECATED
177
        );
178
179
        echo $this->getHeadAttributes();
180
    }
181
182
    public function getHeadAttributes(Environment $environment = null): string
183
    {
184
        if ($this->page instanceof SeoPageAttributesInterface) {
185
            $attributes = $this->page->headAttributes();
186
        } else {
187
            $attributes = new AttributeBag($this->page->getHeadAttributes());
0 ignored issues
show
Deprecated Code introduced by
The method Sonata\SeoBundle\Seo\Seo...ce::getHeadAttributes() has been deprecated with message: use headAttributes()->all() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
188
        }
189
190
        return $this->renderAttributes($attributes, $environment);
191
    }
192
193
    final public function getBodyAttributes(Environment $environment): string
194
    {
195
        return $this->renderAttributes($this->page->bodyAttributes(), $environment);
196
    }
197
198
    /**
199
     * NEXT_MAJOR: remove this method.
200
     *
201
     * @deprecated since 2.0, to be removed in 3.0
202
     */
203
    public function renderLinkCanonical()
204
    {
205
        @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
206
            'The '.__METHOD__.' method is deprecated since 2.0, to be removed in 3.0. '.
207
            'Use '.__NAMESPACE__.'::getLinkCanonical() instead.',
208
            E_USER_DEPRECATED
209
        );
210
211
        echo $this->getLinkCanonical();
212
    }
213
214
    /**
215
     * @return string
216
     */
217
    public function getLinkCanonical()
218
    {
219
        if ($this->page->getLinkCanonical()) {
220
            return sprintf("<link rel=\"canonical\" href=\"%s\"/>\n", $this->page->getLinkCanonical());
221
        }
222
    }
223
224
    /**
225
     * NEXT_MAJOR: remove this method.
226
     *
227
     * @deprecated since 2.0, to be removed in 3.0
228
     */
229
    public function renderLangAlternates()
230
    {
231
        @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
232
            'The '.__METHOD__.' method is deprecated since 2.0, to be removed in 3.0. '.
233
            'Use '.__NAMESPACE__.'::getLangAlternates() instead.',
234
            E_USER_DEPRECATED
235
        );
236
237
        echo $this->getLangAlternates();
238
    }
239
240
    /**
241
     * @return string
242
     */
243
    public function getLangAlternates()
244
    {
245
        $html = '';
246
        foreach ($this->page->getLangAlternates() as $href => $hrefLang) {
247
            $html .= sprintf("<link rel=\"alternate\" href=\"%s\" hreflang=\"%s\"/>\n", $href, $hrefLang);
248
        }
249
250
        return $html;
251
    }
252
253
    /**
254
     * @return string
255
     */
256
    public function getOembedLinks()
257
    {
258
        $html = '';
259
        foreach ($this->page->getOEmbedLinks() as $title => $link) {
260
            $html .= sprintf("<link rel=\"alternate\" type=\"application/json+oembed\" href=\"%s\" title=\"%s\" />\n", $link, $title);
261
        }
262
263
        return $html;
264
    }
265
266
    /**
267
     * @param string $string
268
     *
269
     * @return mixed
270
     */
271
    private function normalize($string)
272
    {
273
        return htmlentities(strip_tags($string), ENT_COMPAT, $this->encoding);
274
    }
275
276
    private function renderAttributes(AttributeBag $attributes, Environment $environment = null): string
277
    {
278
        if (null === $environment) {
279
            return '';
280
        }
281
282
        try {
283
            return trim($environment->render('@SonataSeo/attributes.html.twig', ['attr' => $attributes]));
284
        } catch (Error $exception) {
285
            return '';
286
        }
287
    }
288
}
289