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

src/Kunstmaan/SeoBundle/Twig/SeoTwigExtension.php (4 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')),
0 ignored issues
show
Deprecated Code introduced by
The class Twig_SimpleFunction has been deprecated with message: since Twig 2.7, use "Twig\TwigFunction" instead

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

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

Loading history...
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;
0 ignored issues
show
$url is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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