source: sandbox/newExpressoMail/newExpressoMail/Assetic/Factory/AssetFactory.php @ 7265

Revision 7265, 10.9 KB checked in by gustavo, 12 years ago (diff)

Ticket #0000 - Criado novo modulo para o desenvolvimento do novo ExpressoMail?

  • Property svn:executable set to *
Line 
1<?php
2
3/*
4 * This file is part of the Assetic package, an OpenSky project.
5 *
6 * (c) 2010-2012 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\AssetCollection;
15use Assetic\Asset\AssetCollectionInterface;
16use Assetic\Asset\AssetInterface;
17use Assetic\Asset\AssetReference;
18use Assetic\Asset\FileAsset;
19use Assetic\Asset\GlobAsset;
20use Assetic\Asset\HttpAsset;
21use Assetic\AssetManager;
22use Assetic\Factory\Worker\WorkerInterface;
23use Assetic\FilterManager;
24
25/**
26 * The asset factory creates asset objects.
27 *
28 * @author Kris Wallsmith <kris.wallsmith@gmail.com>
29 */
30class AssetFactory
31{
32    private $root;
33    private $debug;
34    private $output;
35    private $workers;
36    private $am;
37    private $fm;
38
39    /**
40     * Constructor.
41     *
42     * @param string  $root   The default root directory
43     * @param Boolean $debug  Filters prefixed with a "?" will be omitted in debug mode
44     */
45    public function __construct($root, $debug = false)
46    {
47        $this->root      = rtrim($root, '/');
48        $this->debug     = $debug;
49        $this->output    = 'assetic/*';
50        $this->workers   = array();
51    }
52
53    /**
54     * Sets debug mode for the current factory.
55     *
56     * @param Boolean $debug Debug mode
57     */
58    public function setDebug($debug)
59    {
60        $this->debug = $debug;
61    }
62
63    /**
64     * Checks if the factory is in debug mode.
65     *
66     * @return Boolean Debug mode
67     */
68    public function isDebug()
69    {
70        return $this->debug;
71    }
72
73    /**
74     * Sets the default output string.
75     *
76     * @param string $output The default output string
77     */
78    public function setDefaultOutput($output)
79    {
80        $this->output = $output;
81    }
82
83    /**
84     * Adds a factory worker.
85     *
86     * @param WorkerInterface $worker A worker
87     */
88    public function addWorker(WorkerInterface $worker)
89    {
90        $this->workers[] = $worker;
91    }
92
93    /**
94     * Returns the current asset manager.
95     *
96     * @return AssetManager|null The asset manager
97     */
98    public function getAssetManager()
99    {
100        return $this->am;
101    }
102
103    /**
104     * Sets the asset manager to use when creating asset references.
105     *
106     * @param AssetManager $am The asset manager
107     */
108    public function setAssetManager(AssetManager $am)
109    {
110        $this->am = $am;
111    }
112
113    /**
114     * Returns the current filter manager.
115     *
116     * @return FilterManager|null The filter manager
117     */
118    public function getFilterManager()
119    {
120        return $this->fm;
121    }
122
123    /**
124     * Sets the filter manager to use when adding filters.
125     *
126     * @param FilterManager $fm The filter manager
127     */
128    public function setFilterManager(FilterManager $fm)
129    {
130        $this->fm = $fm;
131    }
132
133    /**
134     * Creates a new asset.
135     *
136     * Prefixing a filter name with a question mark will cause it to be
137     * omitted when the factory is in debug mode.
138     *
139     * Available options:
140     *
141     *  * output: An output string
142     *  * name:   An asset name for interpolation in output patterns
143     *  * debug:  Forces debug mode on or off for this asset
144     *  * root:   An array or string of more root directories
145     *
146     * @param array|string $inputs  An array of input strings
147     * @param array|string $filters An array of filter names
148     * @param array        $options An array of options
149     *
150     * @return AssetCollection An asset collection
151     */
152    public function createAsset($inputs = array(), $filters = array(), array $options = array())
153    {
154        if (!is_array($inputs)) {
155            $inputs = array($inputs);
156        }
157
158        if (!is_array($filters)) {
159            $filters = array($filters);
160        }
161
162        if (!isset($options['output'])) {
163            $options['output'] = $this->output;
164        }
165
166        if (!isset($options['vars'])) {
167            $options['vars'] = array();
168        }
169
170        if (!isset($options['debug'])) {
171            $options['debug'] = $this->debug;
172        }
173
174        if (!isset($options['root'])) {
175            $options['root'] = array($this->root);
176        } else {
177            if (!is_array($options['root'])) {
178                $options['root'] = array($options['root']);
179            }
180
181            $options['root'][] = $this->root;
182        }
183
184        if (!isset($options['name'])) {
185            $options['name'] = $this->generateAssetName($inputs, $filters, $options);
186        }
187
188        $asset = $this->createAssetCollection(array(), $options);
189        $extensions = array();
190
191        // inner assets
192        foreach ($inputs as $input) {
193            if (is_array($input)) {
194                // nested formula
195                $asset->add(call_user_func_array(array($this, 'createAsset'), $input));
196            } else {
197                $asset->add($this->parseInput($input, $options));
198                $extensions[pathinfo($input, PATHINFO_EXTENSION)] = true;
199            }
200        }
201
202        // filters
203        foreach ($filters as $filter) {
204            if ('?' != $filter[0]) {
205                $asset->ensureFilter($this->getFilter($filter));
206            } elseif (!$options['debug']) {
207                $asset->ensureFilter($this->getFilter(substr($filter, 1)));
208            }
209        }
210
211        // append variables
212        if (!empty($options['vars'])) {
213            $toAdd = array();
214            foreach ($options['vars'] as $var) {
215                if (false !== strpos($options['output'], '{'.$var.'}')) {
216                    continue;
217                }
218
219                $toAdd[] = '{'.$var.'}';
220            }
221
222            if ($toAdd) {
223                $options['output'] = str_replace('*', '*.'.implode('.', $toAdd), $options['output']);
224            }
225        }
226
227        // append consensus extension if missing
228        if (1 == count($extensions) && !pathinfo($options['output'], PATHINFO_EXTENSION) && $extension = key($extensions)) {
229            $options['output'] .= '.'.$extension;
230        }
231
232        // output --> target url
233        $asset->setTargetPath(str_replace('*', $options['name'], $options['output']));
234
235        // apply workers and return
236        return $this->applyWorkers($asset);
237    }
238
239    public function generateAssetName($inputs, $filters, $options = array())
240    {
241        foreach (array_diff(array_keys($options), array('output', 'debug', 'root')) as $key) {
242            unset($options[$key]);
243        }
244
245        ksort($options);
246
247        return substr(sha1(serialize($inputs).serialize($filters).serialize($options)), 0, 7);
248    }
249
250    /**
251     * Parses an input string string into an asset.
252     *
253     * The input string can be one of the following:
254     *
255     *  * A reference:     If the string starts with an "at" sign it will be interpreted as a reference to an asset in the asset manager
256     *  * An absolute URL: If the string contains "://" or starts with "//" it will be interpreted as an HTTP asset
257     *  * A glob:          If the string contains a "*" it will be interpreted as a glob
258     *  * A path:          Otherwise the string is interpreted as a filesystem path
259     *
260     * Both globs and paths will be absolutized using the current root directory.
261     *
262     * @param string $input   An input string
263     * @param array  $options An array of options
264     *
265     * @return AssetInterface An asset
266     */
267    protected function parseInput($input, array $options = array())
268    {
269        if ('@' == $input[0]) {
270            return $this->createAssetReference(substr($input, 1));
271        }
272
273        if (false !== strpos($input, '://') || 0 === strpos($input, '//')) {
274            return $this->createHttpAsset($input, $options['vars']);
275        }
276
277        if (self::isAbsolutePath($input)) {
278            if ($root = self::findRootDir($input, $options['root'])) {
279                $path = ltrim(substr($input, strlen($root)), '/');
280            } else {
281                $path = null;
282            }
283        } else {
284            $root  = $this->root;
285            $path  = $input;
286            $input = $this->root.'/'.$path;
287        }
288
289        if (false !== strpos($input, '*')) {
290            return $this->createGlobAsset($input, $root, $options['vars']);
291        }
292
293        return $this->createFileAsset($input, $root, $path, $options['vars']);
294    }
295
296    protected function createAssetCollection(array $assets = array(), array $options = array())
297    {
298        return new AssetCollection($assets, array(), null, isset($options['vars']) ? $options['vars'] : array());
299    }
300
301    protected function createAssetReference($name)
302    {
303        if (!$this->am) {
304            throw new \LogicException('There is no asset manager.');
305        }
306
307        return new AssetReference($this->am, $name);
308    }
309
310    protected function createHttpAsset($sourceUrl, $vars)
311    {
312        return new HttpAsset($sourceUrl, array(), false, $vars);
313    }
314
315    protected function createGlobAsset($glob, $root = null, $vars)
316    {
317        return new GlobAsset($glob, array(), $root, $vars);
318    }
319
320    protected function createFileAsset($source, $root = null, $path = null, $vars)
321    {
322        return new FileAsset($source, array(), $root, $path, $vars);
323    }
324
325    protected function getFilter($name)
326    {
327        if (!$this->fm) {
328            throw new \LogicException('There is no filter manager.');
329        }
330
331        return $this->fm->get($name);
332    }
333
334    /**
335     * Filters an asset collection through the factory workers.
336     *
337     * Each leaf asset will be processed first, followed by the asset
338     * collection itself.
339     *
340     * @param AssetCollectionInterface $asset An asset collection
341     *
342     * @return AssetCollectionInterface
343     */
344    private function applyWorkers(AssetCollectionInterface $asset)
345    {
346        foreach ($asset as $leaf) {
347            foreach ($this->workers as $worker) {
348                $retval = $worker->process($leaf);
349
350                if ($retval instanceof AssetInterface && $leaf !== $retval) {
351                    $asset->replaceLeaf($leaf, $retval);
352                }
353            }
354        }
355
356        foreach ($this->workers as $worker) {
357            $retval = $worker->process($asset);
358
359            if ($retval instanceof AssetInterface) {
360                $asset = $retval;
361            }
362        }
363
364        return $asset instanceof AssetCollectionInterface ? $asset : $this->createAssetCollection(array($asset));
365    }
366
367    private static function isAbsolutePath($path)
368    {
369        return '/' == $path[0] || '\\' == $path[0] || (3 < strlen($path) && ctype_alpha($path[0]) && $path[1] == ':' && ('\\' == $path[2] || '/' == $path[2]));
370    }
371
372    /**
373     * Loops through the root directories and returns the first match.
374     *
375     * @param string $path  An absolute path
376     * @param array  $roots An array of root directories
377     *
378     * @return string|null The matching root directory, if found
379     */
380    private static function findRootDir($path, array $roots)
381    {
382        foreach ($roots as $root) {
383            if (0 === strpos($path, $root)) {
384                return $root;
385            }
386        }
387    }
388}
Note: See TracBrowser for help on using the repository browser.