Completed
Push — develop ( 5cb106...80f130 )
by Dmytro
13:36
created

Cache::publishTimeConfig()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 6
nop 1
dl 0
loc 25
rs 9.2088
c 0
b 0
f 0
1
<?php namespace EvolutionCMS;
2
3
/**
4
 * @class: synccache
5
 */
6
class Cache
0 ignored issues
show
Coding Style introduced by
The property $request_time is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
7
{
8
    public $cachePath;
9
    public $showReport;
10
    public $deletedfiles = array();
11
    /**
12
     * @var array
13
     */
14
    public $aliases = array();
15
    /**
16
     * @var array
17
     */
18
    public $parents = array();
19
    /**
20
     * @var array
21
     */
22
    public $aliasVisible = array();
23
    public $request_time;
24
    public $cacheRefreshTime;
25
26
    /**
27
     * synccache constructor.
28
     */
29
    public function __construct()
0 ignored issues
show
Coding Style introduced by
__construct uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
30
    {
31
        $modx = evolutionCMS();
32
33
        $this->request_time = $_SERVER['REQUEST_TIME'] + $modx->config['server_offset_time'];
34
    }
35
36
    /**
37
     * @param string $path
38
     */
39
    public function setCachepath($path)
40
    {
41
        $this->cachePath = $path;
42
    }
43
44
    /**
45
     * @param bool $bool
46
     */
47
    public function setReport($bool)
48
    {
49
        $this->showReport = $bool;
50
    }
51
52
    /**
53
     * @param string $s
54
     * @return string
55
     */
56
    public function escapeSingleQuotes($s)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $s. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
57
    {
58
        if ($s === '') {
59
            return $s;
60
        }
61
        $q1 = array("\\", "'");
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $q1. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
62
        $q2 = array("\\\\", "\\'");
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $q2. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
63
64
        return str_replace($q1, $q2, $s);
65
    }
66
67
    /**
68
     * @param string $s
69
     * @return string
70
     */
71
    public function escapeDoubleQuotes($s)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $s. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
72
    {
73
        $q1 = array("\\", "\"", "\r", "\n", "\$");
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $q1. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
74
        $q2 = array("\\\\", "\\\"", "\\r", "\\n", "\\$");
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $q2. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
75
76
        return str_replace($q1, $q2, $s);
77
    }
78
79
    /**
80
     * @param int|string $id
81
     * @param string $path
82
     * @return string
83
     */
84
    public function getParents($id, $path = '')
85
    { // modx:returns child's parent
86
        $modx = evolutionCMS();
87
        if (empty($this->aliases)) {
88
            $rs = $modx->getDatabase()->select(
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $rs. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
89
                "id, IF(alias='', id, alias) AS alias, parent, alias_visible",
90
                $modx->getDatabase()->getFullTableName('site_content'),
91
                'deleted=0'
92
            );
93
            while ($row = $modx->getDatabase()->getRow($rs)) {
0 ignored issues
show
Bug introduced by
It seems like $rs defined by $modx->getDatabase()->se...content'), 'deleted=0') on line 88 can also be of type boolean; however, EvolutionCMS\Database::getRow() does only seem to accept object<mysqli_result>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
94
                $docid = $row['id'];
95
                $this->aliases[$docid] = $row['alias'];
96
                $this->parents[$docid] = $row['parent'];
97
                $this->aliasVisible[$docid] = $row['alias_visible'];
98
            }
99
        }
100
        if (isset($this->aliases[$id])) {
101
            if ($this->aliasVisible[$id] == 1) {
102
                if ($path != '') {
103
                    $path = $this->aliases[$id] . '/' . $path;
104
                } else {
105
                    $path = $this->aliases[$id];
106
                }
107
            }
108
109
            return $this->getParents($this->parents[$id], $path);
110
        }
111
112
        return $path;
113
    }
114
115
    /**
116
     * @param null|DocumentParser $modx
117
     */
118
    public function emptyCache($modx = null)
0 ignored issues
show
Coding Style introduced by
emptyCache uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
119
    {
120
        if (!($modx instanceof Interfaces\CoreInterface)) {
121
            $modx = $GLOBALS['modx'];
122
        }
123
        if (!isset($this->cachePath)) {
124
            $modx->messageQuit("Cache path not set.");
125
        }
126
127
        $files = glob(realpath($this->cachePath) . '/*.pageCache.php');
128
        $filesincache = count($files);
129
        $deletedfiles = array();
130
        while ($file = array_shift($files)) {
131
            $name = basename($file);
132
            clearstatcache();
133
            if (is_file($file)) {
134
                if (unlink($file)) {
135
                    $deletedfiles[] = $name;
136
                }
137
            }
138
        }
139
        $opcache_restrict_api = trim(ini_get('opcache.restrict_api'));
140
        $opcache_restrict_api = $opcache_restrict_api && mb_stripos(__FILE__, $opcache_restrict_api) !== 0;
141
142
        if (!$opcache_restrict_api && function_exists('opcache_get_status')) {
143
            $opcache = opcache_get_status();
144
            if (!empty($opcache['opcache_enabled'])) {
145
                opcache_reset();
146
            }
147
        }
148
149
        $this->buildCache($modx);
150
151
        $this->publishTimeConfig();
152
153
        // finished cache stuff.
154
        if ($this->showReport == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
155
            global $_lang;
156
            $total = count($deletedfiles);
157
            echo sprintf($_lang['refresh_cache'], $filesincache, $total);
158
            if ($total > 0) {
159
                if (isset($opcache)) {
160
                    echo '<p>Opcache empty.</p>';
161
                }
162
                echo '<p>' . $_lang['cache_files_deleted'] . '</p><ul>';
163
                foreach ($deletedfiles as $deletedfile) {
164
                    echo '<li>' . $deletedfile . '</li>';
165
                }
166
                echo '</ul>';
167
            }
168
        }
169
    }
170
171
    /**
172
     * @param string|int $cacheRefreshTime
173
     */
174
    public function publishTimeConfig($cacheRefreshTime = '')
175
    {
176
        $cacheRefreshTimeFromDB = $this->getCacheRefreshTime();
177
        if (!preg_match('@^[0-9]+$]@', $cacheRefreshTime) || $cacheRefreshTimeFromDB < $cacheRefreshTime) {
178
            $cacheRefreshTime = $cacheRefreshTimeFromDB;
179
        }
180
181
182
        // write the file
183
        $content = '<?php' . "\n";
184
        $content .= '$recent_update=\'' . $this->request_time . '\';' . "\n";
185
        $content .= '$cacheRefreshTime=\'' . $cacheRefreshTime . '\';' . "\n";
186
187
        $filename = $this->cachePath . '/sitePublishing.idx.php';
188
        if (!$handle = fopen($filename, 'w')) {
189
            exit("Cannot open file ({$filename}");
0 ignored issues
show
Coding Style Compatibility introduced by
The method publishTimeConfig() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
190
        }
191
192
        $content .= "\n";
193
194
        // Write $somecontent to our opened file.
195
        if (fwrite($handle, $content) === false) {
196
            exit("Cannot write publishing info file! Make sure the assets/cache directory is writable!");
0 ignored issues
show
Coding Style Compatibility introduced by
The method publishTimeConfig() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
197
        }
198
    }
199
200
    /**
201
     * @return int
202
     */
203
    public function getCacheRefreshTime()
204
    {
205
        $modx = evolutionCMS();
206
207
        // update publish time file
208
        $timesArr = array();
209
210
        $result = $modx->getDatabase()->select(
211
            'MIN(pub_date) AS minpub',
212
            $modx->getDatabase()->getFullTableName('site_content'),
213
            'pub_date>' . $this->request_time
214
        );
215
        if (!$result) {
216
            echo "Couldn't determine next publish event!";
217
        }
218
219
        $minpub = $modx->getDatabase()->getValue($result);
0 ignored issues
show
Bug introduced by
It seems like $result defined by $modx->getDatabase()->se... . $this->request_time) on line 210 can also be of type boolean; however, EvolutionCMS\Database::getValue() does only seem to accept object<mysqli_result>|string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
220
        if ($minpub != null) {
221
            $timesArr[] = $minpub;
222
        }
223
224
        $result = $modx->getDatabase()->select(
225
            'MIN(unpub_date) AS minunpub',
226
            $modx->getDatabase()->getFullTableName('site_content'),
227
            'unpub_date>' . $this->request_time
228
        );
229
        if (!$result) {
230
            echo "Couldn't determine next unpublish event!";
231
        }
232
233
        $minunpub = $modx->getDatabase()->getValue($result);
0 ignored issues
show
Bug introduced by
It seems like $result defined by $modx->getDatabase()->se... . $this->request_time) on line 224 can also be of type boolean; however, EvolutionCMS\Database::getValue() does only seem to accept object<mysqli_result>|string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
234
        if ($minunpub != null) {
235
            $timesArr[] = $minunpub;
236
        }
237
238
        if (isset($this->cacheRefreshTime) && !empty($this->cacheRefreshTime)) {
239
            $timesArr[] = $this->cacheRefreshTime;
240
        }
241
242
        if (count($timesArr) > 0) {
243
            $cacheRefreshTime = min($timesArr);
244
        } else {
245
            $cacheRefreshTime = 0;
246
        }
247
248
        return $cacheRefreshTime;
249
    }
250
251
    /**
252
     * build siteCache file
253
     * @param DocumentParser $modx
254
     * @return boolean success
0 ignored issues
show
Documentation introduced by
Should the return type not be null|boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
255
     */
256
    public function buildCache($modx)
257
    {
258
        $content = "<?php\n";
259
260
        // SETTINGS & DOCUMENT LISTINGS CACHE
261
262
        // get settings
263
        $rs = $modx->getDatabase()->select('*', $modx->getDatabase()->getFullTableName('system_settings'));
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $rs. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
264
        $config = array();
265
        $content .= '$c=&$this->config;';
266
        while (list($key, $value) = $modx->getDatabase()->getRow($rs, 'num')) {
267
            $content .= '$c[\'' . $key . '\']="' . $this->escapeDoubleQuotes($value) . '";';
268
            $config[$key] = $value;
269
        }
270
271
        if ($config['enable_filter']) {
272
            $where = "plugincode LIKE '%phx.parser.class.inc.php%OnParseDocument();%' AND disabled != 1";
273
            $count = $modx->getDatabase()->getRecordCount(
274
                $modx->getDatabase()->select('id', $modx->getDatabase()->getFullTableName('site_plugins'), $where)
275
            );
276
            if ($count) {
277
                $content .= '$this->config[\'enable_filter\']=\'0\';';
278
            }
279
        }
280
281
        if ($config['aliaslistingfolder'] == 1) {
282
            $f['id'] = 'c.id';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$f was never initialized. Although not strictly required by PHP, it is generally a good practice to add $f = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
Comprehensibility introduced by
Avoid variables with short names like $f. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
283
            $f['alias'] = "IF( c.alias='', c.id, c.alias)";
284
            $f['parent'] = 'c.parent';
285
            $f['isfolder'] = 'c.isfolder';
286
            $f['alias_visible'] = 'c.alias_visible';
287
            $from = array();
288
            $from[] = $modx->getDatabase()->getFullTableName('site_content') . ' c';
289
            $from[] = 'LEFT JOIN ' . $modx->getDatabase()->getFullTableName('site_content') . ' p ON p.id=c.parent';
290
            $where = 'c.deleted=0 AND (c.isfolder=1 OR p.alias_visible=0)';
291
            $rs = $modx->getDatabase()->select($f, $from, $where, 'c.parent, c.menuindex');
292
        } else {
293
            $rs = $modx->getDatabase()->select(
294
                "id, IF(alias='', id, alias) AS alias, parent, isfolder, alias_visible",
295
                $modx->getDatabase()->getFullTableName('site_content'),
296
                'deleted=0',
297
                'parent, menuindex'
298
            );
299
        }
300
301
        $use_alias_path = ($config['friendly_urls'] && $config['use_alias_path']) ? 1 : 0;
302
        $tmpPath = '';
303
        $content .= '$this->aliasListing=array();';
304
        $content .= '$a=&$this->aliasListing;';
305
        $content .= '$d=&$this->documentListing;';
306
        $content .= '$m=&$this->documentMap;';
307
        while ($doc = $modx->getDatabase()->getRow($rs)) {
308
            $docid = $doc['id'];
309
            if ($use_alias_path) {
310
                $tmpPath = $this->getParents($doc['parent']);
311
                $alias = (strlen($tmpPath) > 0 ? "$tmpPath/" : '') . $doc['alias'];
312
                $key = $alias;
313
            } else {
314
                $key = $doc['alias'];
315
            }
316
317
            $doc['path'] = $tmpPath;
318
            $content .= '$a[' . $docid . ']=array(\'id\'=>' . $docid . ',\'alias\'=>\'' . $doc['alias'] . '\',\'path\'=>\'' . $doc['path'] . '\',\'parent\'=>' . $doc['parent'] . ',\'isfolder\'=>' . $doc['isfolder'] . ',\'alias_visible\'=>' . $doc['alias_visible'] . ');';
319
            $content .= '$d[\'' . $key . '\']=' . $docid . ';';
320
            $content .= '$m[]=array(' . $doc['parent'] . '=>' . $docid . ');';
321
        }
322
323
        // get content types
324
        $rs = $modx->getDatabase()->select(
325
            'id, contentType',
326
            $modx->getDatabase()->getFullTableName('site_content'),
327
            "contentType!='text/html'"
328
        );
329
        $content .= '$c=&$this->contentTypes;';
330
        while ($doc = $modx->getDatabase()->getRow($rs)) {
331
            $content .= '$c[\'' . $doc['id'] . '\']=\'' . $doc['contentType'] . '\';';
332
        }
333
334
        // WRITE Chunks to cache file
335
        $rs = $modx->getDatabase()->select('*', $modx->getDatabase()->getFullTableName('site_htmlsnippets'));
336
        $content .= '$c=&$this->chunkCache;';
337
        while ($doc = $modx->getDatabase()->getRow($rs)) {
338
            if ($modx->config['minifyphp_incache']) {
339
                $doc['snippet'] = $this->php_strip_whitespace($doc['snippet']);
340
            }
341
            $content .= '$c[\'' . $doc['name'] . '\']=\'' . ($doc['disabled'] ? '' : $this->escapeSingleQuotes($doc['snippet'])) . '\';';
342
        }
343
344
        // WRITE snippets to cache file
345
        $f = 'ss.*, sm.properties as sharedproperties';
346
        $from = $modx->getDatabase()->getFullTableName('site_snippets') . ' ss LEFT JOIN ' .
347
            $modx->getDatabase()->getFullTableName('site_modules') . ' sm on sm.guid=ss.moduleguid';
348
        $rs = $modx->getDatabase()->select($f, $from);
349
        $content .= '$s=&$this->snippetCache;';
350
        while ($row = $modx->getDatabase()->getRow($rs)) {
351
            $key = $row['name'];
352
            if ($row['disabled']) {
353
                $content .= '$s[\'' . $key . '\']=\'return false;\';';
354
            } else {
355
                $value = trim($row['snippet']);
356
                if ($modx->config['minifyphp_incache']) {
357
                    $value = $this->php_strip_whitespace($value);
358
                }
359
                $content .= '$s[\'' . $key . '\']=\'' . $this->escapeSingleQuotes($value) . '\';';
360
                $properties = $modx->parseProperties($row['properties']);
361
                $sharedproperties = $modx->parseProperties($row['sharedproperties']);
362
                $properties = array_merge($sharedproperties, $properties);
363 View Code Duplication
                if (0 < count($properties)) {
364
                    $content .= '$s[\'' . $key . 'Props\']=\'' . $this->escapeSingleQuotes(json_encode($properties)) . '\';';
365
                }
366
            }
367
        }
368
369
        // WRITE plugins to cache file
370
        $f = 'sp.*, sm.properties as sharedproperties';
371
        $from = array();
372
        $from[] = $modx->getDatabase()->getFullTableName('site_plugins') . ' sp';
373
        $from[] = 'LEFT JOIN ' . $modx->getDatabase()->getFullTableName('site_modules') . ' sm on sm.guid=sp.moduleguid';
374
        $rs = $modx->getDatabase()->select($f, $from, 'sp.disabled=0');
375
        $content .= '$p=&$this->pluginCache;';
376
        while ($row = $modx->getDatabase()->getRow($rs)) {
377
            $key = $row['name'];
378
            $value = trim($row['plugincode']);
379
            if ($modx->config['minifyphp_incache']) {
380
                $value = $this->php_strip_whitespace($value);
381
            }
382
            $content .= '$p[\'' . $key . '\']=\'' . $this->escapeSingleQuotes($value) . '\';';
383
            if ($row['properties'] != '' || $row['sharedproperties'] != '') {
384
                $properties = $modx->parseProperties($row['properties']);
385
                $sharedproperties = $modx->parseProperties($row['sharedproperties']);
386
                $properties = array_merge($sharedproperties, $properties);
387 View Code Duplication
                if (0 < count($properties)) {
388
                    $content .= '$p[\'' . $key . 'Props\']=\'' . $this->escapeSingleQuotes(json_encode($properties)) . '\';';
389
                }
390
            }
391
        }
392
393
        // WRITE system event triggers
394
        $f = 'sysevt.name as evtname, event.pluginid, plugin.name as pname';
395
        $from = array();
396
        $from[] = $modx->getDatabase()->getFullTableName('system_eventnames') . ' sysevt';
397
        $from[] = 'INNER JOIN ' . $modx->getDatabase()->getFullTableName('site_plugin_events') . ' event ON event.evtid=sysevt.id';
398
        $from[] = 'INNER JOIN ' . $modx->getDatabase()->getFullTableName('site_plugins') . ' plugin ON plugin.id=event.pluginid';
399
        $rs = $modx->getDatabase()->select($f, $from, 'plugin.disabled=0', 'sysevt.name, event.priority');
400
        $content .= '$e=&$this->pluginEvent;';
401
        $events = array();
402
        while ($row = $modx->getDatabase()->getRow($rs)) {
403
            $evtname = $row['evtname'];
404
            if (!isset($events[$evtname])) {
405
                $events[$evtname] = array();
406
            }
407
            $events[$evtname][] = $row['pname'];
408
        }
409
        foreach ($events as $evtname => $pluginnames) {
410
            $events[$evtname] = $pluginnames;
411
            $content .= '$e[\'' . $evtname . '\']=array(\'' . implode('\',\'',
412
                    $this->escapeSingleQuotes($pluginnames)) . '\');';
413
        }
414
415
        $content .= "\n";
416
417
        // close and write the file
418
        $filename = $this->cachePath . 'siteCache.idx.php';
419
420
        // invoke OnBeforeCacheUpdate event
421
        if ($modx) {
422
            $modx->invokeEvent('OnBeforeCacheUpdate');
423
        }
424
425
        if (@file_put_contents($filename, $content) === false) {
426
            exit("Cannot write main MODX cache file! Make sure the assets/cache directory is writable!");
0 ignored issues
show
Coding Style Compatibility introduced by
The method buildCache() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
427
        }
428
429
        if (!is_file($this->cachePath . '/.htaccess')) {
430
            file_put_contents($this->cachePath . '/.htaccess', "order deny,allow\ndeny from all\n");
431
        }
432
433
        // invoke OnCacheUpdate event
434
        if ($modx) {
435
            $modx->invokeEvent('OnCacheUpdate');
436
        }
437
438
        return true;
439
    }
440
441
    /**
442
     * @param string $source
443
     * @return string
444
     *
445
     * @see http://php.net/manual/en/tokenizer.examples.php
446
     */
447
    public function php_strip_whitespace($source)
0 ignored issues
show
Coding Style introduced by
This method is not in camel caps format.

This check looks for method names that are not written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection seeker becomes databaseConnectionSeeker.

Loading history...
448
    {
449
450
        $source = trim($source);
451
        if (substr($source, 0, 5) !== '<?php') {
452
            $source = '<?php ' . $source;
453
        }
454
455
        $tokens = token_get_all($source);
456
        $_ = '';
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $_. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
457
        $prev_token = 0;
458
        $chars = explode(' ', '( ) ; , = { } ? :');
459
        foreach ($tokens as $i => $token) {
460
            if (is_string($token)) {
461
                if (in_array($token, array('=', ':'))) {
462
                    $_ = trim($_);
463
                } elseif (in_array($token, array('(', '{')) && in_array($prev_token, array(T_IF, T_ELSE, T_ELSEIF))) {
464
                    $_ = trim($_);
465
                }
466
                $_ .= $token;
467
                if ($prev_token == T_END_HEREDOC) {
468
                    $_ .= "\n";
469
                }
470
                continue;
471
            }
472
473
            list($type, $text) = $token;
474
475
            switch ($type) {
476
                case T_COMMENT    :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
477
                case T_DOC_COMMENT:
478
                    break;
479
                case T_WHITESPACE :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
480
                    if ($prev_token != T_END_HEREDOC) {
481
                        $_ = trim($_);
482
                    }
483
                    $lastChar = substr($_, -1);
484
                    if (!in_array($lastChar, $chars)) {// ,320,327,288,284,289
0 ignored issues
show
Unused Code Comprehensibility introduced by
91% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
485
                        if (!in_array($prev_token,
486
                            array(T_FOREACH, T_WHILE, T_FOR, T_BOOLEAN_AND, T_BOOLEAN_OR, T_DOUBLE_ARROW))) {
487
                            $_ .= ' ';
488
                        }
489
                    }
490
                    break;
491
                case T_IS_EQUAL :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
492
                case T_IS_IDENTICAL :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
493
                case T_IS_NOT_EQUAL :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
494
                case T_DOUBLE_ARROW :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
495
                case T_BOOLEAN_AND :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
496
                case T_BOOLEAN_OR :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
497
                case T_START_HEREDOC :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
498
                    if ($prev_token != T_START_HEREDOC) {
499
                        $_ = trim($_);
500
                    }
501
                    $prev_token = $type;
502
                    $_ .= $text;
503
                    break;
504
                default:
505
                    $prev_token = $type;
506
                    $_ .= $text;
507
            }
508
        }
509
        $source = preg_replace(array('@^<\?php@i', '|\s+|', '|<!--|', '|-->|', '|-->\s+<!--|'),
510
            array('', ' ', "\n" . '<!--', '-->' . "\n", '-->' . "\n" . '<!--'), $_);
511
        $source = trim($source);
512
513
        return $source;
514
    }
515
}
516