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\Filter;
13
14use Assetic\Asset\AssetInterface;
15use Assetic\Exception\FilterException;
16use Assetic\Util\FilesystemUtils;
17
18/**
19 * UglifyJs filter.
20 *
21 * @link https://github.com/mishoo/UglifyJS
22 * @author André Roaldseth <andre@roaldseth.net>
23 */
24class UglifyJsFilter extends BaseNodeFilter
25{
26    private $uglifyjsBin;
27    private $nodeBin;
28
29    private $noCopyright;
30    private $beautify;
31    private $unsafe;
32    private $mangle;
33    private $defines;
34
35    /**
36     * @param string $uglifyjsBin Absolute path to the uglifyjs executable
37     * @param string $nodeBin     Absolute path to the folder containg node.js executable
38     */
39    public function __construct($uglifyjsBin = '/usr/bin/uglifyjs', $nodeBin = null)
40    {
41        $this->uglifyjsBin = $uglifyjsBin;
42        $this->nodeBin = $nodeBin;
43    }
44
45    /**
46     * Removes the first block of comments as well
47     * @param bool $noCopyright True to enable
48     */
49    public function setNoCopyright($noCopyright)
50    {
51        $this->noCopyright = $noCopyright;
52    }
53
54    /**
55     * Output indented code
56     * @param bool $beautify True to enable
57     */
58    public function setBeautify($beautify)
59    {
60        $this->beautify = $beautify;
61    }
62
63    /**
64     * Enable additional optimizations that are known to be unsafe in some situations.
65     * @param bool $unsafe True to enable
66     */
67    public function setUnsafe($unsafe)
68    {
69        $this->unsafe = $unsafe;
70    }
71
72    /**
73     * Safely mangle variable and function names for greater file compress.
74     * @param bool $mangle True to enable
75     */
76    public function setMangle($mangle)
77    {
78        $this->mangle = $mangle;
79    }
80
81    public function setDefines(array $defines)
82    {
83        $this->defines = $defines;
84    }
85
86    /**
87     * @see Assetic\Filter\FilterInterface::filterLoad()
88     */
89    public function filterLoad(AssetInterface $asset)
90    {
91    }
92
93    /**
94     * Run the asset through UglifyJs
95     *
96     * @see Assetic\Filter\FilterInterface::filterDump()
97     */
98    public function filterDump(AssetInterface $asset)
99    {
100        $pb = $this->createProcessBuilder(
101            $this->nodeBin
102            ? array($this->nodeBin, $this->uglifyjsBin)
103            : array($this->uglifyjsBin)
104        );
105
106        if ($this->noCopyright) {
107            $pb->add('--no-copyright');
108        }
109
110        if ($this->beautify) {
111            $pb->add('--beautify');
112        }
113
114        if ($this->unsafe) {
115            $pb->add('--unsafe');
116        }
117
118        if (false === $this->mangle) {
119            $pb->add('--no-mangle');
120        }
121
122        if ($this->defines) {
123            foreach ($this->defines as $define) {
124                $pb->add('-d')->add($define);
125            }
126        }
127
128        // input and output files
129        $input  = FilesystemUtils::createTemporaryFile('uglifyjs_in');
130        $output = FilesystemUtils::createTemporaryFile('uglifyjs_out');
131
132        file_put_contents($input, $asset->getContent());
133        $pb->add('-o')->add($output)->add($input);
134
135        $proc = $pb->getProcess();
136        $code = $proc->run();
137        unlink($input);
138
139        if (0 !== $code) {
140            if (file_exists($output)) {
141                unlink($output);
142            }
143
144            if (127 === $code) {
145                throw new \RuntimeException('Path to node executable could not be resolved.');
146            }
147
148            throw FilterException::fromProcess($proc)->setInput($asset->getContent());
149        }
150
151        if (!file_exists($output)) {
152            throw new \RuntimeException('Error creating output file.');
153        }
154
155        $uglifiedJs = file_get_contents($output);
156        unlink($output);
157
158        $asset->setContent($uglifiedJs);
159    }
160}
161