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\Extension\Twig;
13
14use Assetic\Factory\Loader\FormulaLoaderInterface;
15use Assetic\Factory\Resource\ResourceInterface;
16use Psr\Log\LoggerInterface;
17
18/**
19 * Loads asset formulae from Twig templates.
20 *
21 * @author Kris Wallsmith <kris.wallsmith@gmail.com>
22 */
23class TwigFormulaLoader implements FormulaLoaderInterface
24{
25    private $twig;
26    private $logger;
27
28    public function __construct(\Twig_Environment $twig, LoggerInterface $logger = null)
29    {
30        $this->twig = $twig;
31        $this->logger = $logger;
32    }
33
34    public function load(ResourceInterface $resource)
35    {
36        try {
37            $tokens = $this->twig->tokenize(new \Twig_Source($resource->getContent(), (string) $resource));
38            $nodes  = $this->twig->parse($tokens);
39        } catch (\Exception $e) {
40            if ($this->logger) {
41                $this->logger->error(sprintf('The template "%s" contains an error: %s', $resource, $e->getMessage()));
42            }
43
44            return array();
45        }
46
47        return $this->loadNode($nodes);
48    }
49
50    /**
51     * Loads assets from the supplied node.
52     *
53     * @param \Twig_Node $node
54     *
55     * @return array An array of asset formulae indexed by name
56     */
57    private function loadNode(\Twig_Node $node)
58    {
59        $formulae = array();
60
61        if ($node instanceof AsseticNode) {
62            $formulae[$node->getAttribute('name')] = array(
63                $node->getAttribute('inputs'),
64                $node->getAttribute('filters'),
65                array(
66                    'output'  => $node->getAttribute('asset')->getTargetPath(),
67                    'name'    => $node->getAttribute('name'),
68                    'debug'   => $node->getAttribute('debug'),
69                    'combine' => $node->getAttribute('combine'),
70                    'vars'    => $node->getAttribute('vars'),
71                ),
72            );
73        } elseif ($node instanceof AsseticFilterNode) {
74            $name = $node->getAttribute('name');
75
76            $arguments = array();
77            foreach ($node->getNode('arguments') as $argument) {
78                $arguments[] = eval('return '.$this->twig->compile($argument).';');
79            }
80
81            $invoker = $this->twig->getExtension('Assetic\Extension\Twig\AsseticExtension')->getFilterInvoker($name);
82
83            $inputs  = isset($arguments[0]) ? (array) $arguments[0] : array();
84            $filters = $invoker->getFilters();
85            $options = array_replace($invoker->getOptions(), isset($arguments[1]) ? $arguments[1] : array());
86
87            if (!isset($options['name'])) {
88                $options['name'] = $invoker->getFactory()->generateAssetName($inputs, $filters, $options);
89            }
90
91            $formulae[$options['name']] = array($inputs, $filters, $options);
92        }
93
94        foreach ($node as $child) {
95            if ($child instanceof \Twig_Node) {
96                $formulae += $this->loadNode($child);
97            }
98        }
99
100        if ($node->hasAttribute('embedded_templates')) {
101            foreach ($node->getAttribute('embedded_templates') as $child) {
102                $formulae += $this->loadNode($child);
103            }
104        }
105
106        return $formulae;
107    }
108}
109