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\Factory;
13
14use Assetic\Asset\AssetInterface;
15use Assetic\AssetManager;
16use Assetic\Factory\Loader\FormulaLoaderInterface;
17use Assetic\Factory\Resource\ResourceInterface;
18
19/**
20 * A lazy asset manager is a composition of a factory and many formula loaders.
21 *
22 * @author Kris Wallsmith <kris.wallsmith@gmail.com>
23 */
24class LazyAssetManager extends AssetManager
25{
26    private $factory;
27    private $loaders;
28    private $resources;
29    private $formulae;
30    private $loaded;
31    private $loading;
32
33    /**
34     * Constructor.
35     *
36     * @param AssetFactory $factory The asset factory
37     * @param array        $loaders An array of loaders indexed by alias
38     */
39    public function __construct(AssetFactory $factory, $loaders = array())
40    {
41        $this->factory = $factory;
42        $this->loaders = array();
43        $this->resources = array();
44        $this->formulae = array();
45        $this->loaded = false;
46        $this->loading = false;
47
48        foreach ($loaders as $alias => $loader) {
49            $this->setLoader($alias, $loader);
50        }
51    }
52
53    /**
54     * Adds a loader to the asset manager.
55     *
56     * @param string                 $alias  An alias for the loader
57     * @param FormulaLoaderInterface $loader A loader
58     */
59    public function setLoader($alias, FormulaLoaderInterface $loader)
60    {
61        $this->loaders[$alias] = $loader;
62        $this->loaded = false;
63    }
64
65    /**
66     * Adds a resource to the asset manager.
67     *
68     * @param ResourceInterface $resource A resource
69     * @param string            $loader   The loader alias for this resource
70     */
71    public function addResource(ResourceInterface $resource, $loader)
72    {
73        $this->resources[$loader][] = $resource;
74        $this->loaded = false;
75    }
76
77    /**
78     * Returns an array of resources.
79     *
80     * @return array An array of resources
81     */
82    public function getResources()
83    {
84        $resources = array();
85        foreach ($this->resources as $r) {
86            $resources = array_merge($resources, $r);
87        }
88
89        return $resources;
90    }
91
92    /**
93     * Checks for an asset formula.
94     *
95     * @param string $name An asset name
96     *
97     * @return Boolean If there is a formula
98     */
99    public function hasFormula($name)
100    {
101        if (!$this->loaded) {
102            $this->load();
103        }
104
105        return isset($this->formulae[$name]);
106    }
107
108    /**
109     * Returns an asset's formula.
110     *
111     * @param string $name An asset name
112     *
113     * @return array The formula
114     *
115     * @throws \InvalidArgumentException If there is no formula by that name
116     */
117    public function getFormula($name)
118    {
119        if (!$this->loaded) {
120            $this->load();
121        }
122
123        if (!isset($this->formulae[$name])) {
124            throw new \InvalidArgumentException(sprintf('There is no "%s" formula.', $name));
125        }
126
127        return $this->formulae[$name];
128    }
129
130    /**
131     * Sets a formula on the asset manager.
132     *
133     * @param string $name    An asset name
134     * @param array  $formula A formula
135     */
136    public function setFormula($name, array $formula)
137    {
138        $this->formulae[$name] = $formula;
139    }
140
141    /**
142     * Loads formulae from resources.
143     *
144     * @throws \LogicException If a resource has been added to an invalid loader
145     */
146    public function load()
147    {
148        if ($this->loading) {
149            return;
150        }
151
152        if ($diff = array_diff(array_keys($this->resources), array_keys($this->loaders))) {
153            throw new \LogicException('The following loader(s) are not registered: '.implode(', ', $diff));
154        }
155
156        $this->loading = true;
157
158        foreach ($this->resources as $loader => $resources) {
159            foreach ($resources as $resource) {
160                $this->formulae = array_replace($this->formulae, $this->loaders[$loader]->load($resource));
161            }
162        }
163
164        $this->loaded = true;
165        $this->loading = false;
166    }
167
168    public function get($name)
169    {
170        if (!$this->loaded) {
171            $this->load();
172        }
173
174        if (!parent::has($name) && isset($this->formulae[$name])) {
175            list($inputs, $filters, $options) = $this->formulae[$name];
176            $options['name'] = $name;
177            parent::set($name, $this->factory->createAsset($inputs, $filters, $options));
178        }
179
180        return parent::get($name);
181    }
182
183    public function has($name)
184    {
185        if (!$this->loaded) {
186            $this->load();
187        }
188
189        return isset($this->formulae[$name]) || parent::has($name);
190    }
191
192    public function getNames()
193    {
194        if (!$this->loaded) {
195            $this->load();
196        }
197
198        return array_unique(array_merge(parent::getNames(), array_keys($this->formulae)));
199    }
200
201    public function isDebug()
202    {
203        return $this->factory->isDebug();
204    }
205
206    public function getLastModified(AssetInterface $asset)
207    {
208        return $this->factory->getLastModified($asset);
209    }
210}
211