Completed
Push — master ( 1b2ead...87f779 )
by Vitaly
35:28 queued 23:58
created

Module   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 117
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 28.21%

Importance

Changes 25
Bugs 3 Features 8
Metric Value
wmc 14
c 25
b 3
f 8
lcom 1
cbo 4
dl 0
loc 117
ccs 11
cts 39
cp 0.2821
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A prepare() 0 16 3
A cacheDependencies() 0 9 2
B readImport() 0 24 5
B compiler() 0 24 4
1
<?php
2
namespace samsonphp\less;
3
4
use samson\core\ExternalModule;
5
use samsonphp\event\Event;
6
use samsonphp\resource\exception\ResourceNotFound;
7
use samsonphp\resource\Router;
8
9
/**
10
 * SamsonPHP LESS compiler module.
11
 * TODO: Change to file operations to FileManagerInterface
12
 *
13
 * @author Vitaly Iegorov <[email protected]>
14
 */
15
class Module extends ExternalModule
16
{
17
    /** LESS mixin declaration pattern */
18
    const P_IMPORT_DECLARATION = '/@import\s+(\'|\")(?<path>[^\'\"]+)(\'|\");/';
19
20
    /** LESS resource importing dependencies file name */
21
    const DEPENDENCY_CACHE = 'dependencies';
22
23
    /** @var array LESS resources dependencies */
24
    public $dependencies = [];
25
26
    /** @var string Path to LESS resources dependencies cache file */
27
    protected $dependencyCache;
28
29
    /** @var \lessc LESS compiler */
30
    protected $less;
31
32
    /** SamsonFramework load preparation stage handler */
33 6
    public function prepare(array $params = [])
34
    {
35 6
        $moduleCachePath = array_key_exists('cachePath', $params) ? $params['cachePath'] : $this->cache_path;
36 6
        $this->dependencyCache = $moduleCachePath.self::DEPENDENCY_CACHE;
37
38
        // Read previous cache file
39 6
        if (file_exists($this->dependencyCache)) {
40
            $this->dependencies = unserialize(file_get_contents($this->dependencyCache));
41
        }
42
43 6
        $this->less = new \lessc;
44
45 6
        Event::subscribe(Router::E_RESOURCE_COMPILE, [$this, 'compiler']);
46
47 6
        return parent::prepare();
48
    }
49
50
    /**
51
     * Cache LESS resources importing dependency trees.
52
     */
53 1
    public function cacheDependencies()
54
    {
55
        // Create folder
56 1
        if (!file_exists(dirname($this->dependencyCache))) {
57
            @mkdir(dirname($this->dependencyCache), 0777, true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
58
        }
59
60 1
        file_put_contents($this->dependencyCache, serialize($this->dependencies));
61 1
    }
62
63
    /**
64
     * Recursively replace @import in content of the LESS file
65
     *
66
     * @param string $resource Resource full path
67
     * @param string $content  less file content
68
     *
69
     * @return string Content of LESS file with included @imported resources
70
     * @throws ResourceNotFound If importing resource could not be found
71
     */
72
    protected function readImport($resource, $content)
73
    {
74
        // Rewrite imports
75
        $matches = [];
76
        if (preg_match_all(self::P_IMPORT_DECLARATION, $content, $matches)) {
77
            for ($i=0, $size = count($matches[0]); $i < $size; $i++) {
78
                // Build absolute path to imported resource
79
                $path = dirname($resource).DIRECTORY_SEPARATOR.$matches['path'][$i];
80
81
                // Append .less extension according to standard
82
                if (false === ($path = realpath(is_file($path)?$path:$path.'.less'))) {
83
                    throw new ResourceNotFound('Cannot import file: '.$matches['path'][$i]);
84
                }
85
86
                // Add parent to child dependency
87
                $this->dependencies[$path][$resource] = [];
88
89
                // Replace path in LESS @import command with recursive call to this function
90
                $content = str_replace($matches[0][$i], $this->readImport($path, file_get_contents($path)), $content);
91
            }
92
        }
93
94
        return $content;
95
    }
96
97
    /**
98
     * LESS resource compiler.
99
     *
100
     * @param string $resource  Resource full path
101
     * @param string $extension Resource extension
102
     * @param string $content   Compiled output resource content
103
     * @param array $dependencies Collection of compiled resource dependent modules
104
     *
105
     * @throws \Exception
106
     */
107
    public function compiler($resource, &$extension, &$content, &$dependencies)
108
    {
109
        if ($extension === 'less') {
110
            try {
111
                // Rewrite imports
112
                $content = $this->readImport($resource, $content);
113
114
                // Compile LESS content to CSS
115
                $content = $this->less->compile($content);
116
117
                // Switch extension
118
                $extension = 'css';
119
120
                // Return dependencies for this resource
121
                $dependencies = array_key_exists($resource, $this->dependencies)
122
                    ? $this->dependencies[$resource]
123
                    : [];
124
            } catch (\Exception $e) {
125
                //$errorFile = 'cache/error_resourcer'.microtime(true).'.less';
126
                //file_put_contents($errorFile, $output);
127
                throw new \Exception('Failed compiling LESS in "' . $resource . '":' . "\n" . $e->getMessage());
128
            }
129
        }
130
    }
131
}
132