1<?php
2
3/*
4 * This file is part of the Assetic package, an OpenSky project.
5 *
6 * (c) 2010-2014 OpenSky Project Inc
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Assetic\Asset;
13
14use Assetic\Cache\CacheInterface;
15use Assetic\Filter\FilterInterface;
16use Assetic\Filter\HashableInterface;
17
18/**
19 * Caches an asset to avoid the cost of loading and dumping.
20 *
21 * @author Kris Wallsmith <kris.wallsmith@gmail.com>
22 */
23class AssetCache implements AssetInterface
24{
25    private $asset;
26    private $cache;
27
28    public function __construct(AssetInterface $asset, CacheInterface $cache)
29    {
30        $this->asset = $asset;
31        $this->cache = $cache;
32    }
33
34    public function ensureFilter(FilterInterface $filter)
35    {
36        $this->asset->ensureFilter($filter);
37    }
38
39    public function getFilters()
40    {
41        return $this->asset->getFilters();
42    }
43
44    public function clearFilters()
45    {
46        $this->asset->clearFilters();
47    }
48
49    public function load(FilterInterface $additionalFilter = null)
50    {
51        $cacheKey = self::getCacheKey($this->asset, $additionalFilter, 'load');
52        if ($this->cache->has($cacheKey)) {
53            $this->asset->setContent($this->cache->get($cacheKey));
54
55            return;
56        }
57
58        $this->asset->load($additionalFilter);
59        $this->cache->set($cacheKey, $this->asset->getContent());
60    }
61
62    public function dump(FilterInterface $additionalFilter = null)
63    {
64        $cacheKey = self::getCacheKey($this->asset, $additionalFilter, 'dump');
65        if ($this->cache->has($cacheKey)) {
66            return $this->cache->get($cacheKey);
67        }
68
69        $content = $this->asset->dump($additionalFilter);
70        $this->cache->set($cacheKey, $content);
71
72        return $content;
73    }
74
75    public function getContent()
76    {
77        return $this->asset->getContent();
78    }
79
80    public function setContent($content)
81    {
82        $this->asset->setContent($content);
83    }
84
85    public function getSourceRoot()
86    {
87        return $this->asset->getSourceRoot();
88    }
89
90    public function getSourcePath()
91    {
92        return $this->asset->getSourcePath();
93    }
94
95    public function getSourceDirectory()
96    {
97        return $this->asset->getSourceDirectory();
98    }
99
100    public function getTargetPath()
101    {
102        return $this->asset->getTargetPath();
103    }
104
105    public function setTargetPath($targetPath)
106    {
107        $this->asset->setTargetPath($targetPath);
108    }
109
110    public function getLastModified()
111    {
112        return $this->asset->getLastModified();
113    }
114
115    public function getVars()
116    {
117        return $this->asset->getVars();
118    }
119
120    public function setValues(array $values)
121    {
122        $this->asset->setValues($values);
123    }
124
125    public function getValues()
126    {
127        return $this->asset->getValues();
128    }
129
130    /**
131     * Returns a cache key for the current asset.
132     *
133     * The key is composed of everything but an asset's content:
134     *
135     *  * source root
136     *  * source path
137     *  * target url
138     *  * last modified
139     *  * filters
140     *
141     * @param AssetInterface  $asset            The asset
142     * @param FilterInterface $additionalFilter Any additional filter being applied
143     * @param string          $salt             Salt for the key
144     *
145     * @return string A key for identifying the current asset
146     */
147    private static function getCacheKey(AssetInterface $asset, FilterInterface $additionalFilter = null, $salt = '')
148    {
149        if ($additionalFilter) {
150            $asset = clone $asset;
151            $asset->ensureFilter($additionalFilter);
152        }
153
154        $cacheKey  = $asset->getSourceRoot();
155        $cacheKey .= $asset->getSourcePath();
156        $cacheKey .= $asset->getTargetPath();
157        $cacheKey .= $asset->getLastModified();
158
159        foreach ($asset->getFilters() as $filter) {
160            if ($filter instanceof HashableInterface) {
161                $cacheKey .= $filter->hash();
162            } else {
163                $cacheKey .= serialize($filter);
164            }
165        }
166
167        if ($values = $asset->getValues()) {
168            asort($values);
169            $cacheKey .= serialize($values);
170        }
171
172        return md5($cacheKey.$salt);
173    }
174}
175