Completed
Push — master ( aba493...5356ed )
by Ruud
315:38 queued 305:00
created

src/Kunstmaan/SeoBundle/Twig/SeoTwigExtension.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Kunstmaan\SeoBundle\Twig;
4
5
use Doctrine\ORM\EntityManager;
6
use Kunstmaan\AdminBundle\Entity\AbstractEntity;
7
use Kunstmaan\NodeBundle\Entity\AbstractPage;
8
use Kunstmaan\SeoBundle\Entity\Seo;
9
use Psr\Cache\CacheItemPoolInterface;
10
use Twig_Extension;
11
12
/**
13
 * Twig extensions for Seo
14
 */
15
class SeoTwigExtension extends Twig_Extension
16
{
17
    /**
18
     * @var EntityManager
19
     */
20
    protected $em;
21
22
    /**
23
     * Website title defined in your parameters
24
     *
25
     * @var string
26
     */
27
    private $websiteTitle;
28
29
    /**
30
     * Saves querying the db multiple times, if you happen to use any of the defined
31
     * functions more than once in your templates
32
     *
33
     * @var array
34
     */
35
    private $seoCache = [];
36
37
    /**
38
     * @var CacheItemPoolInterface
39
     */
40
    private $requestCache;
41
42
    /**
43
     * @param EntityManager $em
44
     */
45
    public function __construct(EntityManager $em)
46
    {
47
        $this->em = $em;
48
    }
49
50
    /**
51
     * Returns a list of functions to add to the existing list.
52
     *
53
     * @return array An array of functions
54
     */
55
    public function getFunctions()
56
    {
57
        return array(
58
            new \Twig_SimpleFunction('render_seo_metadata_for', array($this, 'renderSeoMetadataFor'), array('is_safe' => array('html'), 'needs_environment' => true)),
59
            new \Twig_SimpleFunction('get_seo_for', array($this, 'getSeoFor')),
60
            new \Twig_SimpleFunction('get_title_for', array($this, 'getTitleFor')),
61
            new \Twig_SimpleFunction('get_title_for_page_or_default', array($this, 'getTitleForPageOrDefault')),
62
            new \Twig_SimpleFunction('get_absolute_url', array($this, 'getAbsoluteUrl')),
63
            new \Twig_SimpleFunction('get_image_dimensions', array($this, 'getImageDimensions')),
64
        );
65
    }
66
67
    /**
68
     * Validates the $url value as URL (according to » http://www.faqs.org/rfcs/rfc2396), optionally with required components.
69
     * It will just return the url if it's valid. If it starts with '/', the $host will be prepended.
70
     *
71
     * @param string $url
72
     * @param string $host
0 ignored issues
show
Should the type for parameter $host not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
73
     *
74
     * @return string
0 ignored issues
show
Should the return type not be string|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
75
     */
76
    public function getAbsoluteUrl($url, $host = null)
77
    {
78
        $validUrl = filter_var($url, FILTER_VALIDATE_URL);
79
        $host = rtrim($host, '/');
80
81
        if (!$validUrl === false) {
82
            // The url is valid
83
            return $url;
84
        }
85
86
        // Prepend with $host if $url starts with "/"
87
        if (strpos($url, '/') === 0) {
88
            return $url = $host.$url;
89
        }
90
91
        return false;
92
    }
93
94
    /**
95
     * @param AbstractPage $entity
96
     *
97
     * @return Seo
98
     */
99
    public function getSeoFor(AbstractPage $entity)
100
    {
101
        $key = md5(\get_class($entity).$entity->getId());
102
103
        if (!\array_key_exists($key, $this->seoCache)) {
104
            $seo = $this->em->getRepository('KunstmaanSeoBundle:Seo')->findOrCreateFor($entity);
105
            $this->seoCache[$key] = $seo;
106
        }
107
108
        return $this->seoCache[$key];
109
    }
110
111
    /**
112
     * The first value that is not null or empty will be returned.
113
     *
114
     * @param AbstractPage $entity the entity for which you want the page title
115
     *
116
     * @return string The page title. Will look in the SEO meta first, then the NodeTranslation, then the page.
117
     */
118
    public function getTitleFor(AbstractPage $entity)
119
    {
120
        $arr = array();
121
122
        $arr[] = $this->getSeoTitle($entity);
123
124
        $arr[] = $entity->getTitle();
125
126
        return $this->getPreferredValue($arr);
127
    }
128
129
    /**
130
     * @param AbstractPage $entity
131
     * @param null|string  $default if given we'll return this text if no SEO title was found
132
     *
133
     * @return string
134
     */
135
    public function getTitleForPageOrDefault(AbstractPage $entity = null, $default = null)
136
    {
137
        if (\is_null($entity)) {
138
            return $default;
139
        }
140
141
        $arr = array();
142
143
        $arr[] = $this->getSeoTitle($entity);
144
145
        $arr[] = $default;
146
147
        $arr[] = $entity->getTitle();
148
149
        return $this->getPreferredValue($arr);
150
    }
151
152
    /**
153
     * @param \Twig_Environment $environment
154
     * @param AbstractEntity    $entity      The entity
155
     * @param mixed             $currentNode The current node
156
     * @param string            $template    The template
157
     *
158
     * @return string
159
     */
160
    public function renderSeoMetadataFor(\Twig_Environment $environment, AbstractEntity $entity, $currentNode = null, $template = 'KunstmaanSeoBundle:SeoTwigExtension:metadata.html.twig')
161
    {
162
        $seo = $this->getSeoFor($entity);
163
        $template = $environment->loadTemplate($template);
164
165
        return $template->render(
166
            array(
167
                'seo' => $seo,
168
                'entity' => $entity,
169
                'currentNode' => $currentNode,
170
            )
171
        );
172
    }
173
174
    /**
175
     * @param array $values
176
     *
177
     * @return string
178
     */
179
    protected function getPreferredValue(array $values)
180
    {
181
        foreach ($values as $v) {
182
            if (!\is_null($v) && !empty($v)) {
183
                return $v;
184
            }
185
        }
186
187
        return '';
188
    }
189
190
    /**
191
     * @param AbstractPage $entity
192
     *
193
     * @return null|string
194
     */
195
    private function getSeoTitle(AbstractPage $entity = null)
196
    {
197
        if (\is_null($entity)) {
198
            return null;
199
        }
200
201
        $seo = $this->getSeoFor($entity);
202
        if (!\is_null($seo)) {
203
            $title = $seo->getMetaTitle();
204
            if (!empty($title)) {
205
                return str_replace('%websitetitle%', $this->getWebsiteTitle(), $title);
206
            }
207
        }
208
209
        return null;
210
    }
211
212
    /**
213
     * Gets the Website title defined in your parameters.
214
     *
215
     * @return string
216
     */
217
    public function getWebsiteTitle()
218
    {
219
        return $this->websiteTitle;
220
    }
221
222
    /**
223
     * Sets the Website title defined in your parameters.
224
     *
225
     * @param string $websiteTitle the website title
226
     *
227
     * @return self
228
     */
229
    public function setWebsiteTitle($websiteTitle)
230
    {
231
        $this->websiteTitle = $websiteTitle;
232
233
        return $this;
234
    }
235
236
    /**
237
     * @param $src
238
     *
239
     * @return array
240
     */
241
    public function getImageDimensions($src)
242
    {
243
        list($width, $height) = $this->getImageSize($src);
244
245
        return ['width' => $width, 'height' => $height];
246
    }
247
248
    public function setRequestCache(CacheItemPoolInterface $cacheService)
249
    {
250
        $this->requestCache = $cacheService;
251
    }
252
253
    /**
254
     * @return CacheItemPoolInterface
255
     */
256
    public function getRequestCache()
257
    {
258
        return $this->requestCache;
259
    }
260
261
    private function getImageSize($src)
262
    {
263
        try {
264
            $cache = $this->getRequestCache();
265
            if (null === $cache) {
266
                return getimagesize($src);
267
            }
268
269
            $cachedImageSizes = $cache->getItem(md5($src));
270
            if (!$cachedImageSizes->isHit()) {
271
                $sizes = getimagesize($src);
272
273
                $cachedImageSizes->set($sizes);
274
                $cache->save($cachedImageSizes);
275
            }
276
277
            return $cachedImageSizes->get();
278
        } catch (\Exception $e) {
279
            return [null, null];
280
        }
281
    }
282
}
283