aboutsummaryrefslogtreecommitdiff
path: root/lib/classes/assets/SASSCompiler.php
blob: a8b459cd40bf64bc270a7f8635fae619733217c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<?php
namespace Assets;

use Assets;
use StudipCacheFactory;
use Studip;

use ScssPhp\ScssPhp\Compiler as ScssCompiler;
use ScssPhp\ScssPhp\Formatter;

/**
 * SCSS Compiler for assets.
 *
 * Uses scssphp <https://scssphp.github.io/scssphp/>.
 *
 * @author  Jan-Hendrik Willms <tleilax+studip@gmail.com>
 * @license GPL2 or any later version
 * @since   Stud.IP 4.4
 */
class SASSCompiler implements Compiler
{
    const CACHE_KEY = '/assets/sass-prefix';

    private static $instance = null;

    /**
     * Returns an instance of the compiler
     * @return Assets\SASSCompiler instance
     */
    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Private constructor to enforce singleton.
     */
    private function __construct()
    {
    }

    /**
     * Compiles a scss string. This method will add all neccessary imports
     * and variables for Stud.IP so almost all mixins and variables of the
     * core system can be used. This includes colors and icons.
     *
     * @param String $input      Scss content to compile
     * @param Array  $variables Additional variables for the LESS compilation
     * @return String containing the generated CSS
     */
    public function compile($input, array $variables = [])
    {
        $scss = $this->getPrefix() . $input;

        $variables['image-path'] = '"' . Assets::url('images') . '"';

        $compiler = new ScssCompiler();
        $compiler->addImportPath("{$GLOBALS['STUDIP_BASE_PATH']}/resources/");
        $compiler->setVariables($variables);
        if (Studip\ENV === 'production') {
            $compiler->setFormatter(Formatter\Crunched::class);
        } else {
            $compiler->setFormatter(Formatter\Expanded::class);
            $compiler->setLineNumberStyle(ScssCompiler::LINE_COMMENTS);
        }
        $css = $compiler->compile($scss);
        $css = preg_replace('~/\*.*?\*/~s', '', $css);
        $css = trim($css);
        return $css;
    }

    /**
     * Generates the less prefix containing the variables and mixins of the
     * Stud.IP core system.
     * This prefix will be cached in Stud.IP's cache in order to minimize
     * disk accesses.
     *
     * @return String containing the neccessary prefix
     */
    private function getPrefix()
    {
        $cache = StudipCacheFactory::getCache();

        $prefix = $cache->read(self::CACHE_KEY);

        if ($prefix === false) {
            $prefix = '';

            // Load mixins and change relative to absolute filenames
            $mixin_file = $GLOBALS['STUDIP_BASE_PATH'] . '/resources/assets/stylesheets/mixins.scss';
            foreach (file($mixin_file) as $mixin) {
                if (!preg_match('/@import "(.*)";/', $mixin, $match)) {
                    continue;
                }

                $core_file = "assets/stylesheets/{$match[1]}";
                $prefix .= sprintf('@import "%s";' . "\n", $core_file);
            }

            // Add adjusted image paths
            $prefix .= sprintf('$image-path: "%s";', Assets::url('images')) . "\n";
            $prefix .= '$icon-path: "#{$image-path}/icons";' . "\n";

            $cache->write(self::CACHE_KEY, $prefix);
        }

        return $prefix;
    }
}