Completed
Push — master ( 0e8bf0...ca3a42 )
by Vitaly
02:16
created

Router::src_replace_callback()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 31
Code Lines 13

Duplication

Lines 6
Ratio 19.35 %

Importance

Changes 4
Bugs 0 Features 2
Metric Value
cc 6
eloc 13
c 4
b 0
f 2
nc 6
nop 1
dl 6
loc 31
rs 8.439

1 Method

Rating   Name   Duplication   Size   Complexity  
A Router::injectJS() 0 9 1
1
<?php
2
namespace samsonphp\resource;
3
4
use samson\core\ExternalModule;
5
use samsonphp\event\Event;
6
use samsonphp\resource\exception\ResourceNotFound;
7
8
/**
9
 * Resource router for serving static resource from unreachable web-root paths.
10
 *
11
 * @author Vitaly Iegorov <[email protected]>
12
 * @author Nikita Kotenko <[email protected]>
13
 */
14
class Router extends ExternalModule
15
{
16
    /** Event showing that new gather resource file was created */
17
    const EVENT_CREATED = 'resource.created';
18
    /** Event showing that new gather resource file was created */
19
    const EVENT_START_GENERATE_RESOURCES = 'resource.start.generate.resources';
20
21
    /** @var string Marker for inserting generated JS link in template */
22
    public $jsMarker = '</body>';
23
    /** @var string Marker for inserting generated CSS link in template */
24
    public $cssMarker = '</head>';
25
    /** Cached resources path collection */
26
    public $cached = array();
27
    /** Collection of updated cached resources for notification of changes */
28
    public $updated = array();
29
30
    /** Identifier */
31
    protected $id = STATIC_RESOURCE_HANDLER;
32
33
    /** Pointer to processing module */
34
    private $currentModule;
35
    /** @var string Current processed resource */
36
    private $currentResource;
37
38
    /** @see ModuleConnector::init() */
39
    public function init(array $params = array())
40
    {
41
        parent::init($params);
42
43
        $moduleList = $this->system->module_stack;
44
45
        Event::fire(self::EVENT_START_GENERATE_RESOURCES, array(&$moduleList));
46
47
        $this->generateResources($moduleList);
48
49
        // Subscribe to core rendered event
50
        $this->system->subscribe('core.rendered', array($this, 'renderer'));
51
    }
52
53
    public function gatherResources($path)
0 ignored issues
show
Unused Code introduced by
The parameter $path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
54
    {
55
        // we need to read all resources at specified path
56
        // we need to gather all CSS resources into one file
57
        // we need to gather all LESS resources into one file
58
        // we need to gather all SASS resources into one file
59
        // we need to gather all COFFEE resources into one file
60
        // we need to gather all JS resources into one file
61
        // we need to be able to include all files separately into template in development
62
        // we need handlers/events for each resource type gathered with less and our approach
63
        // we have problems that our variables are splitted around modules to make this work
64
        // we need to gather all files and then parse on come up with different solution
65
66
    }
67
68
    public function gatherResources($path)
0 ignored issues
show
Unused Code introduced by
The parameter $path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
69
    {
70
        // we need to read all resources at specified path
71
        // we need to gather all CSS resources into one file
72
        // we need to gather all LESS resources into one file
73
        // we need to gather all SASS resources into one file
74
        // we need to gather all COFFEE resources into one file
75
        // we need to gather all JS resources into one file
76
        // we need to be able to include all files separately into template in development
77
        // we need handlers/events for each resource type gathered with less and our approach
78
        // we have problems that our variables are splitted around modules to make this work
79
        // we need to gather all files and then parse on come up with different solution
80
81
    }
82
83
    public function generateResources($moduleList, $templatePath = 'default')
84
    {
85
        $dir = str_replace(array('/', '.'), '_', $templatePath);
86
87
        // Cache main web resources
88
        foreach (array(array('js'), array('css', 'less'), array('coffee')) as $rts) {
89
            // Get first resource type as extension
90
            $rt = $rts[0];
91
92
            $hash_name = '';
93
94
            // Iterate gathered namespaces for their resources
95
            /** @var Module $module */
96
            foreach ($moduleList as $id => $module) {
97
                // If necessary resources has been collected
98
                foreach ($rts as $_rt) {
99
                    if (isset($module->resourceMap->$_rt)) {
100
                        foreach ($module->resourceMap->$_rt as $resource) {
101
                            // Created string with last resource modification time
102
                            $hash_name .= filemtime($resource);
103
                        }
104
                    }
105
                }
106
            }
107
108
            // Get hash that's describes resource status
109
            $hash_name = md5($hash_name) . '.' . $rt;
110
111
            $file = $hash_name;
112
113
            // If cached file does not exists
114
            if ($this->cache_refresh($file, true, $dir)) {
0 ignored issues
show
Unused Code introduced by
The call to Router::cache_refresh() has too many arguments starting with $dir.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
115
                // Read content of resource files
116
                $content = '';
117
                foreach ($moduleList as $id => $module) {
118
                    $this->currentModule = $module;
119
                    // If this ns has resources of specified type
120
                    foreach ($rts as $_rt) {
121
                        if (isset($module->resourceMap->$_rt)) {
122
                            foreach ($module->resourceMap->$_rt as $resource) {
123
                                // Store current processing resource
124
                                $this->currentResource = $resource;
125
                                // Read resource file
126
                                $c = file_get_contents($resource);
127
                                // Rewrite url in css
128
                                if ($rt === 'css') {
129
                                    $c = preg_replace_callback('/url\s*\(\s*(\'|\")?([^\)\s\'\"]+)(\'|\")?\s*\)/i',
130
                                        array($this, 'replaceUrlCallback'), $c);
131
                                }
132
                                // Gather processed resource text together
133
                                $content .= "\n\r" . $c;
134
                            }
135
                        }
136
                    }
137
                }
138
139
                // Fire event that new resource has been generated
140
                Event::fire(self::EVENT_CREATED, array($rt, &$content, &$file, &$this));
141
142
                // Fix updated resource file with new path to it
143
                $this->updated[$rt] = $file;
144
145
                // Create cache file
146
                file_put_contents($file, $content);
147
            }
148
149
            // Save path to resource cache
150
            $this->cached[$rt][$templatePath] = __SAMSON_CACHE_PATH . $this->id . '/' . $dir . '/' . $hash_name;
151
        }
152
    }
153
154
    /**
155
     * Core render handler for including CSS and JS resources to html
156
     *
157
     * @param string $view   View content
158
     * @param array  $data   View data
159
     * @param null   $module Module instance
160
     *
161
     * @return string Processed view content
162
     */
163
    public function renderer(&$view, $data = array(), $module = null)
164
    {
165
        $templateId = isset($this->cached['css'][$this->system->template()])
166
            ? $this->system->template()
167
            : 'default';
168
169
        // Define resource urls
170
        $css = Resource::getWebRelativePath($this->cached['css'][$templateId]);
171
        $js = Resource::getWebRelativePath($this->cached['js'][$templateId]);
172
173
        // TODO: Прорисовка зависит от текущего модуля, сделать єто через параметр прорисовщика
174
        // If called from compressor
175
        if ($module->id() === 'compressor') {
0 ignored issues
show
Bug introduced by
The method id cannot be called on $module (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
176
            $templateId = isset($this->cached['css'][$data['file']]) ? $data['file'] : 'default';
177
            $css = url()->base() . basename($this->cached['css'][$templateId]);
178
            $js = url()->base() . basename($this->cached['js'][$templateId]);
179
        }
180
181
        // Inject resource links
182
        return $view = $this->injectCSS($this->injectJS($view, $js), $css);
183
    }
184
185
    /**
186
     * Inject CSS link into view.
187
     *
188
     * @param string $view View code
189
     * @param string $path Resource path
190
     *
191
     * @return string Modified view
192
     */
193
    protected function injectCSS($view, $path)
194
    {
195
        // Put css link at the end of <head> page block
196
        return str_ireplace(
197
            $this->cssMarker,
198
            "\n" . '<link type="text/css" rel="stylesheet" href="' . $path . '">' . "\n" . $this->cssMarker,
199
            $view
200
        );
201
    }
202
203
    /**
204
     * Inject JS link into view.
205
     *
206
     * @param string $view View code
207
     * @param string $path Resource path
208
     *
209
     * @return string Modified view
210
     */
211
    protected function injectJS($view, $path)
212
    {
213
        // Put javascript link in the end of the document
214
        return str_ireplace(
215
            $this->jsMarker,
216
            "\n" . '<script async type="text/javascript" src="' . $path . '"></script>' . "\n" . $this->jsMarker,
217
            $view
218
        );
219
    }
220
221
    /**
222
     * Callback for CSS url(...) rewriting.
223
     *
224
     * @param array $matches Regular expression matches collection
225
     *
226
     * @return string Rewritten url(..) with static resource handler url
227
     * @throws ResourceNotFound
228
     */
229
    public function replaceUrlCallback($matches)
230
    {
231
        // If we have found static resource path definition and its not inline
232
        if (array_key_exists(2, $matches) && strpos($matches[2], 'data:') === false) {
233
            // Store static resource path
234
            $url = $matches[2];
235
236
            // Ignore preprocessor vars
237
            // TODO: This is totally wrong need to come up with decision
238
            if (strpos($url, '@') !== false) {
239
                return $matches[0];
240
            }
241
242
            // Remove possible GET parameters from resource path
243 View Code Duplication
            if (($getStart = stripos($url, '?')) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
244
                $url = substr($url, 0, $getStart);
245
            }
246
247
            // Remove possible HASH parameters from resource path
248 View Code Duplication
            if (($getStart = stripos($url, '#')) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
249
                $url = substr($url, 0, $getStart);
250
            }
251
252
            // Build path to static resource handler
253
            return 'url("/' . $this->id . '/?p='
254
            . Resource::getProjectRelativePath($url, dirname($this->currentResource))
255
            . '")';
256
        }
257
258
        return $matches[0];
259
    }
260
}
261