Module::cacheDependencies()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 3
Bugs 1 Features 1
Metric Value
c 3
b 1
f 1
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
namespace samsonphp\less;
3
4
use samson\core\ExternalModule;
5
use samsonframework\filemanager\FileManagerInterface;
6
use samsonframework\localfilemanager\LocalFileManager;
7
use samsonphp\event\Event;
8
use samsonphp\resource\exception\ResourceNotFound;
9
use samsonphp\resource\Router;
10
11
/**
12
 * SamsonPHP LESS compiler module.
13
 *
14
 * @author Vitaly Iegorov <[email protected]>
15
 */
16
class Module extends ExternalModule
17
{
18
    /** LESS mixin declaration pattern */
19
    const P_IMPORT_DECLARATION = '/@import\s+(\'|\")(?<path>[^\'\"]+)(\'|\");/';
20
21
    /** LESS resource importing dependencies file name */
22
    const DEPENDENCY_CACHE = 'dependencies';
23
24
    /** @var array LESS resources dependencies */
25
    public $dependencies = [];
26
27
    /** @var string Path to LESS resources dependencies cache file */
28
    protected $dependencyCache;
29
30
    /** @var \lessc LESS compiler */
31
    protected $less;
32
33
    /** @var FileManagerInterface */
34
    protected $fileManager;
35
36
    /** SamsonFramework load preparation stage handler */
37 6
    public function prepare(array $params = [])
38
    {
39 6
        $moduleCachePath = array_key_exists('cachePath', $params) ? $params['cachePath'] : $this->cache_path;
40 6
        $this->dependencyCache = $moduleCachePath.self::DEPENDENCY_CACHE;
41
42
        // Load file manager
43 6
        $this->fileManager = array_key_exists('fileManager', $params) ? $params['fileManager'] : new LocalFileManager();
44
45
        // Read previous cache file
46 6
        if ($this->fileManager->exists($this->dependencyCache)) {
47 1
            $this->dependencies = unserialize($this->fileManager->read($this->dependencyCache));
48 1
        }
49
50 6
        $this->less = new \lessc;
51
52 6
        Event::subscribe(Router::E_RESOURCE_COMPILE, [$this, 'compiler']);
53 6
        Event::subscribe(Router::E_FINISHED, [$this, 'cacheDependencies']);
54
55 6
        return parent::prepare();
56
    }
57
58
    /**
59
     * Cache LESS resources importing dependency trees.
60
     */
61 2
    public function cacheDependencies()
62
    {
63 2
        $this->fileManager->write($this->dependencyCache, serialize($this->dependencies));
64 2
    }
65
66
    /**
67
     * Recursively replace import in content of the LESS file
68
     *
69
     * @param string $resource Resource full path
70
     * @param string $content  less file content
71
     *
72
     * @return string Content of LESS file with included imported resources
73
     * @throws ResourceNotFound If importing resource could not be found
74
     */
75 4
    protected function readImport($resource, $content)
76
    {
77
        // Rewrite imports
78 4
        $matches = [];
79 4
        if (preg_match_all(self::P_IMPORT_DECLARATION, $content, $matches)) {
80 3
            for ($i=0, $size = count($matches[0]); $i < $size; $i++) {
81
                // Build absolute path to imported resource
82 3
                $path = dirname($resource).DIRECTORY_SEPARATOR.$matches['path'][$i];
83
84
                // Append .less extension according to standard
85 3
                if (false === ($path = realpath($this->fileManager->exists($path)?$path:$path.'.less'))) {
86 1
                    throw new ResourceNotFound('Cannot import file: '.$matches['path'][$i]);
87
                }
88
89
                // Add parent to child dependency
90 2
                $this->dependencies[$path][$resource] = [];
91
92
                // Replace path in LESS @import command with recursive call to this function
93 2
                $content = str_replace($matches[0][$i], $this->readImport($path, $this->fileManager->read($path)), $content);
94 2
            }
95 2
        }
96
97 3
        return $content;
98
    }
99
100
    /**
101
     * LESS resource compiler.
102
     *
103
     * @param string $resource  Resource full path
104
     * @param string $extension Resource extension
105
     * @param string $content   Compiled output resource content
106
     * @param array $dependencies Collection of compiled resource dependent modules
107
     *
108
     * @throws \Exception
109
     */
110 4
    public function compiler($resource, &$extension, &$content, &$dependencies)
111
    {
112 4
        if ($extension === 'less') {
113
            try {
114
                // Rewrite imports
115 4
                $content = $this->readImport($resource, $content);
116
117
                // Compile LESS content to CSS
118 3
                $content = $this->less->compile($content);
119
120
                // Switch extension
121 2
                $extension = 'css';
122
123
                // Return dependencies for this resource
124 2
                $dependencies = array_key_exists($resource, $this->dependencies)
125 2
                    ? $this->dependencies[$resource]
126 2
                    : [];
127 4
            } catch (\Exception $e) {
128
                //$errorFile = 'cache/error_resourcer'.microtime(true).'.less';
129
                //file_put_contents($errorFile, $output);
130 2
                throw new \Exception('Failed compiling LESS in "' . $resource . '":' . "\n" . $e->getMessage());
131
            }
132 2
        }
133 2
    }
134
}
135