mirror of
https://github.com/getgrav/grav.git
synced 2025-12-05 15:29:57 +01:00
Compare commits
169 Commits
1.0.0-rc.5
...
1.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4e0c06ea8 | ||
|
|
0c807b6108 | ||
|
|
3a47d6a580 | ||
|
|
52947b3a2c | ||
|
|
eacfc798f4 | ||
|
|
5c0e5f3c01 | ||
|
|
985141b842 | ||
|
|
1aac2ab95d | ||
|
|
aa7d5ddf59 | ||
|
|
e87505378d | ||
|
|
53f097c2b3 | ||
|
|
6ea7fe9dba | ||
|
|
0206f1b0c7 | ||
|
|
ef9f2c77dd | ||
|
|
822292f541 | ||
|
|
ec08cd9374 | ||
|
|
8fb4063cf2 | ||
|
|
8a2b444c48 | ||
|
|
9c6f243902 | ||
|
|
d5bd99b363 | ||
|
|
5554c07cbf | ||
|
|
acd95aac6f | ||
|
|
8ad5f2624d | ||
|
|
8adc0e1c17 | ||
|
|
fab66cf3a5 | ||
|
|
5df48e7a68 | ||
|
|
079a8c5728 | ||
|
|
d9196426a1 | ||
|
|
2f686f5b74 | ||
|
|
c4b5df20a9 | ||
|
|
06608a6d3c | ||
|
|
fd63911faf | ||
|
|
66a1e55867 | ||
|
|
af2eb2e75d | ||
|
|
9b4f32cafd | ||
|
|
9179fbd1a2 | ||
|
|
24ea7f1f55 | ||
|
|
9b95053110 | ||
|
|
71ffb9c72f | ||
|
|
f29f698f61 | ||
|
|
f1f8579a0b | ||
|
|
4ca8fab750 | ||
|
|
b80ed731b0 | ||
|
|
23a9a73600 | ||
|
|
dc8c0b6522 | ||
|
|
e695b1942c | ||
|
|
3f543e7e84 | ||
|
|
7f6f9e82e3 | ||
|
|
51529eb0ce | ||
|
|
05b24a4b75 | ||
|
|
ca5819489f | ||
|
|
1d2acf8096 | ||
|
|
98278e965b | ||
|
|
7bc990688c | ||
|
|
b86aa6d473 | ||
|
|
dba7347c1e | ||
|
|
fa52e18e3f | ||
|
|
b605753a6d | ||
|
|
0af4fb351c | ||
|
|
90edf95077 | ||
|
|
ab3843442a | ||
|
|
023b9dd708 | ||
|
|
0ac882314e | ||
|
|
0fe9264582 | ||
|
|
b1e16b2206 | ||
|
|
a67c1780c1 | ||
|
|
1170f2f58d | ||
|
|
199c0a08ea | ||
|
|
84ad152536 | ||
|
|
5b0f905ae3 | ||
|
|
a2bba8f09d | ||
|
|
2007975428 | ||
|
|
e484997515 | ||
|
|
af5c52c52f | ||
|
|
f3d0e10378 | ||
|
|
b33ab43ff9 | ||
|
|
c580399db6 | ||
|
|
00d8717d7c | ||
|
|
6e2f4607a6 | ||
|
|
3a7abeb18b | ||
|
|
84a5984c65 | ||
|
|
1465c26b1f | ||
|
|
b399d8e3b9 | ||
|
|
b5c04bdc9b | ||
|
|
b4725800c3 | ||
|
|
2b1a102efa | ||
|
|
500c548af4 | ||
|
|
fc7017f822 | ||
|
|
5b254f4cf8 | ||
|
|
43783f3ce6 | ||
|
|
ae39aabee1 | ||
|
|
df7a94148b | ||
|
|
63890661fe | ||
|
|
793ac1a1bb | ||
|
|
77db54c50d | ||
|
|
b259927348 | ||
|
|
e8972a6aa5 | ||
|
|
8d8420c0d6 | ||
|
|
7a6707f597 | ||
|
|
b0ec66cce8 | ||
|
|
edfd7db88b | ||
|
|
fb3e68e16e | ||
|
|
080ab9e289 | ||
|
|
f67e441b83 | ||
|
|
9c07d69c45 | ||
|
|
13207f13ad | ||
|
|
34f83ebde2 | ||
|
|
14ed805656 | ||
|
|
385233c508 | ||
|
|
8a3b987cd5 | ||
|
|
bdd17fc56a | ||
|
|
29b3c081ee | ||
|
|
b1d80b6c5f | ||
|
|
e00560f81a | ||
|
|
20f17130a2 | ||
|
|
583156d2f3 | ||
|
|
88f36f4987 | ||
|
|
965c8cfbe9 | ||
|
|
b8f00243e6 | ||
|
|
1d97f98515 | ||
|
|
9764cf3f65 | ||
|
|
1f5df81496 | ||
|
|
5f76a0255c | ||
|
|
17f3ca6eba | ||
|
|
b29d79738b | ||
|
|
020cdd7324 | ||
|
|
1e39f3b22d | ||
|
|
37035a488d | ||
|
|
745b418cd7 | ||
|
|
2a02c8bc4f | ||
|
|
a15e063b92 | ||
|
|
2051fed5b7 | ||
|
|
268714863e | ||
|
|
60c6532307 | ||
|
|
9adf81294d | ||
|
|
3033818589 | ||
|
|
09ed480628 | ||
|
|
5dd1554e5d | ||
|
|
748f329c8e | ||
|
|
7228b25393 | ||
|
|
90fcf448c7 | ||
|
|
dd2ddfeb40 | ||
|
|
ac3396e6c4 | ||
|
|
d888dcd085 | ||
|
|
184cb9ea3a | ||
|
|
997c772b7c | ||
|
|
bc4a09f80d | ||
|
|
55890b4fd8 | ||
|
|
6fdfaccc92 | ||
|
|
76e01e7aea | ||
|
|
87378562ea | ||
|
|
7e540e0623 | ||
|
|
b0c171f453 | ||
|
|
67fefb53ad | ||
|
|
0ff5dc0016 | ||
|
|
ae17a77789 | ||
|
|
5f11ae7482 | ||
|
|
4d33eb2173 | ||
|
|
fe7873ddbe | ||
|
|
f95a4f5cc6 | ||
|
|
f973b61b5e | ||
|
|
f1d4192ae7 | ||
|
|
fb500d3e1c | ||
|
|
14347ebf88 | ||
|
|
3e0188e40b | ||
|
|
b82f17f367 | ||
|
|
3f28dc59ea | ||
|
|
77deea8ad4 | ||
|
|
e27f638fe3 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -16,12 +16,15 @@ logs/*
|
||||
!logs/.*
|
||||
images/*
|
||||
!images/.*
|
||||
user/accounts/*
|
||||
!user/accounts/.*
|
||||
user/data/*
|
||||
!user/data/.*
|
||||
user/plugins/*
|
||||
!user/plugins/.*
|
||||
user/themes/*
|
||||
!user/themes/.*
|
||||
user/localhost/config/security.yaml
|
||||
|
||||
# OS Generated
|
||||
.DS_Store*
|
||||
|
||||
@@ -54,7 +54,7 @@ RewriteRule \.md$ error [F]
|
||||
# Block all direct access to files and folders beginning with a dot
|
||||
RewriteRule (^\.|/\.) - [F]
|
||||
# Block access to specific files in the root folder
|
||||
RewriteRule ^(LICENSE|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess)$ error [F]
|
||||
RewriteRule ^(LICENSE.txt|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess)$ error [F]
|
||||
## End - Security
|
||||
|
||||
</IfModule>
|
||||
|
||||
61
CHANGELOG.md
61
CHANGELOG.md
@@ -1,3 +1,58 @@
|
||||
# v1.0.0
|
||||
## 12/11/2015
|
||||
|
||||
1. [](#new)
|
||||
* Add new link attributes via markdown media
|
||||
* Added setters to set state of CSS/JS pipelining
|
||||
* Added `user/accounts` to `.gitignore`
|
||||
* Added configurable permissions option for Image cache
|
||||
1. [](#improved)
|
||||
* Hungarian translation updated
|
||||
* Refactored Theme initialization for improved flexibility
|
||||
* Wrapped security section of account blueprints in an 'super user' authorize check
|
||||
* Minor performance optimizations
|
||||
* Updated core page blueprints with markdown preview option
|
||||
* Added useful cache info output to Debugbar
|
||||
* Added `iconv` polyfill library used by Symfony 2.8
|
||||
* Force lowercase of username in a few places for case sensitive filesystems
|
||||
1. [](#bugfix)
|
||||
* Fix for GPM problems "Call to a member function set() on null"
|
||||
* Fix for individual asset pipeline values not functioning
|
||||
* Fix `Page::copy()` and `Page::move()` to support multiple moves at once
|
||||
* Fixed page moving of a page with no content
|
||||
* Fix for wrong ordering when moving many pages
|
||||
* Escape root path in page medium files to work with special characters
|
||||
* Add missing parent constructor to Themes class
|
||||
* Fix missing file error in `bin/grav sandbox` command
|
||||
* Fixed changelog differ when upgrading Grav
|
||||
* Fixed a logic error in `Validation->validate()`
|
||||
* Make `$container` available in `setup.php` to fix multi-site
|
||||
|
||||
# v1.0.0-rc.6
|
||||
## 12/01/2015
|
||||
|
||||
1. [](#new)
|
||||
* Refactor Config classes for improved performance!
|
||||
* Refactor Data classes to use `NestedArrayAccess` instead of `DataMutatorTrait`
|
||||
* Added support for `classes` and `id` on medium objects to set CSS values
|
||||
* Data objects: Allow function call chaining
|
||||
* Data objects: Lazy load blueprints only if needed
|
||||
* Automatically create unique security salt for each configuration
|
||||
* Added Hungarian translation
|
||||
* Added support for User groups
|
||||
1. [](#improved)
|
||||
* Improved robots.txt to disallow crawling of non-user folders
|
||||
* Nonces only generated once per action and process
|
||||
* Added IP into Nonce string calculation
|
||||
* Nonces now use random string with random salt to improve performance
|
||||
* Improved list form handling #475
|
||||
* Vendor library updates
|
||||
1. [](#bugfix)
|
||||
* Fixed help output for `bin/plugin`
|
||||
* Fix for nested logic for lists and form parsing #273
|
||||
* Fix for array form fields and last entry not getting deleted
|
||||
* Should not be able to set parent to self #308
|
||||
|
||||
# v1.0.0-rc.5
|
||||
## 11/20/2015
|
||||
|
||||
@@ -6,7 +61,7 @@
|
||||
* Implemented the ability for Plugins to provide their own CLI commands through `bin/plugin`
|
||||
* Added Croatian translation
|
||||
* Added missing `umask_fix` property to `system.yaml`
|
||||
* Added current theme's config to global config. E.g. `config.theme.dropdown_enabled`
|
||||
* Added current theme's config to global config. E.g. `config.theme.dropdown_enabled`
|
||||
* Added `append_url_extension` option to system config & page headers
|
||||
* Users have a new `state` property to allow disabling/banning
|
||||
* Added new `Page.relativePagePath()` helper method
|
||||
@@ -53,7 +108,7 @@
|
||||
|
||||
1. [](#new)
|
||||
* New Page collection options! `@self.parent, @self.siblings, @self.descendants` + more
|
||||
* Whitelist of file types for fallback route functionality (images by default)
|
||||
* White list of file types for fallback route functionality (images by default)
|
||||
1. [](#improved)
|
||||
* Assets switched from defines to streams
|
||||
1. [](#bugfix)
|
||||
@@ -78,7 +133,7 @@
|
||||
* German language improvements
|
||||
* Updated bundled composer
|
||||
1. [](#bugfix)
|
||||
* Accept variety of `true` values in `User.authorize()` method
|
||||
* Accept variety of `true` values in `User.authorize()` method
|
||||
* Fix for `Validation` throwing an error if no label set
|
||||
|
||||
# v1.0.0-rc.1
|
||||
|
||||
@@ -103,7 +103,7 @@ What you mainly want to know is that:
|
||||
|
||||
# License
|
||||
|
||||
See [LICENSE](LICENSE)
|
||||
See [LICENSE](LICENSE.txt)
|
||||
|
||||
|
||||
[gitflow-model]: http://nvie.com/posts/a-successful-git-branching-model/
|
||||
|
||||
2
bin/gpm
2
bin/gpm
@@ -40,8 +40,6 @@ if (!function_exists('curl_version')) {
|
||||
$grav = Grav::instance(array('loader' => $autoload));
|
||||
$grav['config']->init();
|
||||
$grav['streams'];
|
||||
$grav['plugins']->init();
|
||||
$grav['themes']->init();
|
||||
|
||||
$app = new Application('Grav Package Manager', GRAV_VERSION);
|
||||
$app->addCommands(array(
|
||||
|
||||
@@ -44,7 +44,7 @@ $grav['plugins']->init();
|
||||
$grav['themes']->init();
|
||||
|
||||
$app = new Application('Grav Plugins Commands', GRAV_VERSION);
|
||||
$pattern = '/([A-Z]\w+Command\.php)$/usm';
|
||||
$pattern = '([A-Z]\w+Command\.php)';
|
||||
|
||||
// get arguments and strip the application name
|
||||
if (null === $argv) {
|
||||
@@ -70,7 +70,7 @@ if (!$name) {
|
||||
$output->writeln('');
|
||||
$output->writeln("<red>Example:</red>");
|
||||
$output->writeln(" {$bin} error log -l 1 --trace");
|
||||
$list = Folder::all('plugins://', ['compare' => 'Pathname', 'pattern' => '\/cli\/' . $pattern]);
|
||||
$list = Folder::all('plugins://', ['compare' => 'Pathname', 'pattern' => '/\/cli\/' . $pattern . '$/usm']);
|
||||
|
||||
if (count($list)) {
|
||||
$available = [];
|
||||
@@ -101,7 +101,7 @@ if ($plugin === null) {
|
||||
$path = 'plugins://' . $name . '/cli';
|
||||
|
||||
try {
|
||||
$commands = Folder::all($path, ['compare' => 'Filename', 'pattern' => $pattern]);
|
||||
$commands = Folder::all($path, ['compare' => 'Filename', 'pattern' => '/' . $pattern . '$/usm']);
|
||||
} catch (\RuntimeException $e) {
|
||||
$output->writeln("<red>No Console Commands for <white>'{$name}'</white> where found in <white>'{$path}'</white></red>");
|
||||
exit;
|
||||
|
||||
@@ -7,21 +7,22 @@
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": ">=5.4.0",
|
||||
"twig/twig": "~1.16",
|
||||
"twig/twig": "~1.23",
|
||||
"erusev/parsedown-extra": "~0.7",
|
||||
"symfony/yaml": "~2.7",
|
||||
"symfony/console": "~2.7",
|
||||
"symfony/event-dispatcher": "~2.7",
|
||||
"symfony/var-dumper": "~2.7",
|
||||
"doctrine/cache": "~1.4",
|
||||
"filp/whoops": "1.2.*@dev",
|
||||
"symfony/yaml": "~2.8",
|
||||
"symfony/console": "~2.8",
|
||||
"symfony/event-dispatcher": "~2.8",
|
||||
"symfony/var-dumper": "~2.8",
|
||||
"symfony/polyfill-iconv": "~1.0",
|
||||
"doctrine/cache": "~1.5",
|
||||
"filp/whoops": "1.1.10",
|
||||
"monolog/monolog": "~1.0",
|
||||
"gregwar/image": "~2.0",
|
||||
"ircmaxell/password-compat": "1.0.*",
|
||||
"mrclay/minify": "~2.2",
|
||||
"donatj/phpuseragentparser": "~0.3",
|
||||
"pimple/pimple": "~3.0",
|
||||
"rockettheme/toolbox": "1.1.*",
|
||||
"rockettheme/toolbox": "~1.2",
|
||||
"maximebf/debugbar": "~1.10"
|
||||
},
|
||||
"autoload": {
|
||||
|
||||
282
composer.lock
generated
282
composer.lock
generated
@@ -4,21 +4,21 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "e1db721096772d41f16003b39b47c85a",
|
||||
"content-hash": "294dd2282a332d96b19d163ad08e7ba7",
|
||||
"hash": "09fcc6b4528be7d9c8af68a66e85f0b2",
|
||||
"content-hash": "69bee250cbc5160401d50cc47c8d6aba",
|
||||
"packages": [
|
||||
{
|
||||
"name": "doctrine/cache",
|
||||
"version": "v1.5.1",
|
||||
"version": "v1.5.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/cache.git",
|
||||
"reference": "2b9cec5a5e722010cbebc91713d4c11eaa064d5e"
|
||||
"reference": "47c7128262da274f590ae6f86eb137a7a64e82af"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/cache/zipball/2b9cec5a5e722010cbebc91713d4c11eaa064d5e",
|
||||
"reference": "2b9cec5a5e722010cbebc91713d4c11eaa064d5e",
|
||||
"url": "https://api.github.com/repos/doctrine/cache/zipball/47c7128262da274f590ae6f86eb137a7a64e82af",
|
||||
"reference": "47c7128262da274f590ae6f86eb137a7a64e82af",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -75,7 +75,7 @@
|
||||
"cache",
|
||||
"caching"
|
||||
],
|
||||
"time": "2015-11-02 18:35:48"
|
||||
"time": "2015-12-03 10:50:37"
|
||||
},
|
||||
{
|
||||
"name": "donatj/phpuseragentparser",
|
||||
@@ -169,16 +169,16 @@
|
||||
},
|
||||
{
|
||||
"name": "erusev/parsedown-extra",
|
||||
"version": "0.7.0",
|
||||
"version": "0.7.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/erusev/parsedown-extra.git",
|
||||
"reference": "11a44e076d02ffcc4021713398a60cd73f78b6f5"
|
||||
"reference": "0db5cce7354e4b76f155d092ab5eb3981c21258c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/erusev/parsedown-extra/zipball/11a44e076d02ffcc4021713398a60cd73f78b6f5",
|
||||
"reference": "11a44e076d02ffcc4021713398a60cd73f78b6f5",
|
||||
"url": "https://api.github.com/repos/erusev/parsedown-extra/zipball/0db5cce7354e4b76f155d092ab5eb3981c21258c",
|
||||
"reference": "0db5cce7354e4b76f155d092ab5eb3981c21258c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -209,20 +209,20 @@
|
||||
"parsedown",
|
||||
"parser"
|
||||
],
|
||||
"time": "2015-01-25 14:52:34"
|
||||
"time": "2015-11-01 10:19:22"
|
||||
},
|
||||
{
|
||||
"name": "filp/whoops",
|
||||
"version": "dev-master",
|
||||
"version": "1.1.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filp/whoops.git",
|
||||
"reference": "50a288b51058fa94cf5b37cfa4277535983cc9d5"
|
||||
"reference": "72538eeb70bbfb11964412a3d098d109efd012f7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/50a288b51058fa94cf5b37cfa4277535983cc9d5",
|
||||
"reference": "50a288b51058fa94cf5b37cfa4277535983cc9d5",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/72538eeb70bbfb11964412a3d098d109efd012f7",
|
||||
"reference": "72538eeb70bbfb11964412a3d098d109efd012f7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -267,7 +267,7 @@
|
||||
"whoops",
|
||||
"zf2"
|
||||
],
|
||||
"time": "2015-11-14 20:08:27"
|
||||
"time": "2015-06-29 05:42:04"
|
||||
},
|
||||
{
|
||||
"name": "gregwar/cache",
|
||||
@@ -404,25 +404,25 @@
|
||||
},
|
||||
{
|
||||
"name": "maximebf/debugbar",
|
||||
"version": "v1.10.5",
|
||||
"version": "v1.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/maximebf/php-debugbar.git",
|
||||
"reference": "30e53e8a28284b69dd223c9f5ee8957befd72636"
|
||||
"reference": "07741d84d39d10f00551c94284cdefcc69703e77"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/30e53e8a28284b69dd223c9f5ee8957befd72636",
|
||||
"reference": "30e53e8a28284b69dd223c9f5ee8957befd72636",
|
||||
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/07741d84d39d10f00551c94284cdefcc69703e77",
|
||||
"reference": "07741d84d39d10f00551c94284cdefcc69703e77",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"psr/log": "~1.0",
|
||||
"symfony/var-dumper": "~2.6"
|
||||
"psr/log": "^1.0",
|
||||
"symfony/var-dumper": "^2.6|^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
"phpunit/phpunit": "^4.0|^5.0"
|
||||
},
|
||||
"suggest": {
|
||||
"kriswallsmith/assetic": "The best way to manage assets",
|
||||
@@ -432,12 +432,12 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.10-dev"
|
||||
"dev-master": "1.11-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"DebugBar": "src/"
|
||||
"psr-4": {
|
||||
"DebugBar\\": "src/DebugBar/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@@ -449,14 +449,19 @@
|
||||
"name": "Maxime Bouroumeau-Fuseau",
|
||||
"email": "maxime.bouroumeau@gmail.com",
|
||||
"homepage": "http://maximebf.com"
|
||||
},
|
||||
{
|
||||
"name": "Barry vd. Heuvel",
|
||||
"email": "barryvdh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Debug bar in the browser for php application",
|
||||
"homepage": "https://github.com/maximebf/php-debugbar",
|
||||
"keywords": [
|
||||
"debug"
|
||||
"debug",
|
||||
"debugbar"
|
||||
],
|
||||
"time": "2015-10-19 20:35:12"
|
||||
"time": "2015-12-10 09:50:24"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
@@ -666,16 +671,16 @@
|
||||
},
|
||||
{
|
||||
"name": "rockettheme/toolbox",
|
||||
"version": "1.1.4",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rockettheme/toolbox.git",
|
||||
"reference": "ff677d8f66d1addd3590d0cb85bcbaff4174d9c9"
|
||||
"reference": "0c7a3b4b6e4d73be8512e89f7acde6899334b7f2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/rockettheme/toolbox/zipball/ff677d8f66d1addd3590d0cb85bcbaff4174d9c9",
|
||||
"reference": "ff677d8f66d1addd3590d0cb85bcbaff4174d9c9",
|
||||
"url": "https://api.github.com/repos/rockettheme/toolbox/zipball/0c7a3b4b6e4d73be8512e89f7acde6899334b7f2",
|
||||
"reference": "0c7a3b4b6e4d73be8512e89f7acde6899334b7f2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -711,29 +716,30 @@
|
||||
"php",
|
||||
"rockettheme"
|
||||
],
|
||||
"time": "2015-10-15 23:27:40"
|
||||
"time": "2015-11-24 17:04:24"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "5efd632294c8320ea52492db22292ff853a43766"
|
||||
"reference": "d232bfc100dfd32b18ccbcab4bcc8f28697b7e41"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/5efd632294c8320ea52492db22292ff853a43766",
|
||||
"reference": "5efd632294c8320ea52492db22292ff853a43766",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/d232bfc100dfd32b18ccbcab4bcc8f28697b7e41",
|
||||
"reference": "d232bfc100dfd32b18ccbcab4bcc8f28697b7e41",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
"php": ">=5.3.9",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/event-dispatcher": "~2.1",
|
||||
"symfony/process": "~2.1"
|
||||
"symfony/event-dispatcher": "~2.1|~3.0.0",
|
||||
"symfony/process": "~2.1|~3.0.0"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "For using the console logger",
|
||||
@@ -743,13 +749,16 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
"dev-master": "2.8-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Console\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@@ -767,20 +776,20 @@
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-20 14:38:46"
|
||||
"time": "2015-11-30 12:35:10"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "87a5db5ea887763fa3a31a5471b512ff1596d9b8"
|
||||
"reference": "a5eb815363c0388e83247e7e9853e5dbc14999cc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/87a5db5ea887763fa3a31a5471b512ff1596d9b8",
|
||||
"reference": "87a5db5ea887763fa3a31a5471b512ff1596d9b8",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a5eb815363c0388e83247e7e9853e5dbc14999cc",
|
||||
"reference": "a5eb815363c0388e83247e7e9853e5dbc14999cc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -788,10 +797,10 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/config": "~2.0,>=2.0.5",
|
||||
"symfony/dependency-injection": "~2.6",
|
||||
"symfony/expression-language": "~2.6",
|
||||
"symfony/stopwatch": "~2.3"
|
||||
"symfony/config": "~2.0,>=2.0.5|~3.0.0",
|
||||
"symfony/dependency-injection": "~2.6|~3.0.0",
|
||||
"symfony/expression-language": "~2.6|~3.0.0",
|
||||
"symfony/stopwatch": "~2.3|~3.0.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/dependency-injection": "",
|
||||
@@ -800,13 +809,16 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
"dev-master": "2.8-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\EventDispatcher\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@@ -824,24 +836,140 @@
|
||||
],
|
||||
"description": "Symfony EventDispatcher Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-11 09:39:48"
|
||||
"time": "2015-10-30 20:15:42"
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-dumper",
|
||||
"version": "v2.7.6",
|
||||
"name": "symfony/polyfill-iconv",
|
||||
"version": "v1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/var-dumper.git",
|
||||
"reference": "eb033050050916b6bfa51be71009ef67b16046c9"
|
||||
"url": "https://github.com/symfony/polyfill-iconv.git",
|
||||
"reference": "21a18998764e569c1675efc7191887130b319605"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/eb033050050916b6bfa51be71009ef67b16046c9",
|
||||
"reference": "eb033050050916b6bfa51be71009ef67b16046c9",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/21a18998764e569c1675efc7191887130b319605",
|
||||
"reference": "21a18998764e569c1675efc7191887130b319605",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Iconv\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for the Iconv extension",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"iconv",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2015-11-04 20:28:58"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "0b6a8940385311a24e060ec1fe35680e17c74497"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0b6a8940385311a24e060ec1fe35680e17c74497",
|
||||
"reference": "0b6a8940385311a24e060ec1fe35680e17c74497",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for the Mbstring extension",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"mbstring",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2015-11-04 20:28:58"
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-dumper",
|
||||
"version": "v2.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/var-dumper.git",
|
||||
"reference": "e6f3855005f2bfad7d7e72431d374a6478893fe3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/e6f3855005f2bfad7d7e72431d374a6478893fe3",
|
||||
"reference": "e6f3855005f2bfad7d7e72431d374a6478893fe3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"twig/twig": "~1.20|~2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-symfony_debug": ""
|
||||
@@ -849,7 +977,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
"dev-master": "2.8-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -858,7 +986,10 @@
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\VarDumper\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@@ -880,20 +1011,20 @@
|
||||
"debug",
|
||||
"dump"
|
||||
],
|
||||
"time": "2015-10-25 17:17:38"
|
||||
"time": "2015-11-18 13:45:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v2.7.6",
|
||||
"version": "v2.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "eca9019c88fbe250164affd107bc8057771f3f4d"
|
||||
"reference": "f79824187de95064a2f5038904c4d7f0227fedb5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/eca9019c88fbe250164affd107bc8057771f3f4d",
|
||||
"reference": "eca9019c88fbe250164affd107bc8057771f3f4d",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/f79824187de95064a2f5038904c4d7f0227fedb5",
|
||||
"reference": "f79824187de95064a2f5038904c4d7f0227fedb5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -902,13 +1033,16 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
"dev-master": "2.8-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Yaml\\": ""
|
||||
}
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@@ -926,7 +1060,7 @@
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-11 09:39:48"
|
||||
"time": "2015-11-30 12:35:10"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
@@ -993,9 +1127,7 @@
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"filp/whoops": 20
|
||||
},
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
|
||||
@@ -54,7 +54,7 @@ RewriteRule \.md$ error [F]
|
||||
# Block all direct access to files and folders beginning with a dot
|
||||
RewriteRule (^\.|/\.) - [F]
|
||||
# Block access to specific files in the root folder
|
||||
RewriteRule ^(LICENSE|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess)$ error [F]
|
||||
RewriteRule ^(LICENSE.txt|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess)$ error [F]
|
||||
## End - Security
|
||||
|
||||
</IfModule>
|
||||
|
||||
@@ -27,7 +27,7 @@ url.rewrite-if-not-file = (
|
||||
)
|
||||
|
||||
#IMPROVING SECURITY
|
||||
$HTTP["url"] =~ "^/grav_path/(LICENSE|composer.json|composer.lock|nginx.conf|web.config)$" {
|
||||
$HTTP["url"] =~ "^/grav_path/(LICENSE.txt|composer.json|composer.lock|nginx.conf|web.config)$" {
|
||||
url.access-deny = ("")
|
||||
}
|
||||
$HTTP["url"] =~ "^/grav_path/(.git|cache|bin|logs|backup)/(.*)" {
|
||||
|
||||
@@ -38,7 +38,7 @@ server {
|
||||
# deny running scripts inside user folder
|
||||
location ~* /user/.*\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
|
||||
# deny access to specific files in the root folder
|
||||
location ~ /(LICENSE|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess) { return 403; }
|
||||
location ~ /(LICENSE.txt|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess) { return 403; }
|
||||
## End - Security
|
||||
}
|
||||
|
||||
|
||||
11
robots.txt
11
robots.txt
@@ -1,2 +1,11 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
Disallow: /backup/
|
||||
Disallow: /bin/
|
||||
Disallow: /cache/
|
||||
Disallow: /grav/
|
||||
Disallow: /logs/
|
||||
Disallow: /system/
|
||||
Disallow: /vendor/
|
||||
Disallow: /user/
|
||||
Allow: /user/pages/
|
||||
Allow: /user/themes/
|
||||
|
||||
@@ -516,6 +516,17 @@ form:
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
twig.umask_fix:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.TWIG_UMASK_FIX
|
||||
help: PLUGIN_ADMIN.TWIG_UMASK_FIX_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.ASSETS
|
||||
@@ -688,6 +699,17 @@ form:
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
images.cache_perms:
|
||||
type: select
|
||||
size: small
|
||||
label: PLUGIN_ADMIN.CACHE_PERMS
|
||||
help: PLUGIN_ADMIN.CACHE_PERMS_HELP
|
||||
highlight: '0755'
|
||||
options:
|
||||
1: '0755'
|
||||
0: '0775'
|
||||
|
||||
|
||||
images.debug:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.IMAGES_DEBUG
|
||||
@@ -745,13 +767,14 @@ form:
|
||||
|
||||
fields:
|
||||
session.enabled:
|
||||
type: toggle
|
||||
type: hidden
|
||||
label: PLUGIN_ADMIN.ENABLED
|
||||
help: PLUGIN_ADMIN.SESSION_ENABLED_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
default: true
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
|
||||
7
system/blueprints/media/meta.yaml
Normal file
7
system/blueprints/media/meta.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
alt_text:
|
||||
type: string
|
||||
label: Alt Text
|
||||
8
system/blueprints/media/move.yaml
Normal file
8
system/blueprints/media/move.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
route:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.PAGE
|
||||
classes: fancy
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
8
system/blueprints/media/rename.yaml
Normal file
8
system/blueprints/media/rename.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
new_file_name:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN_PRO.NEW_FILE_NAME
|
||||
validate:
|
||||
required: true
|
||||
@@ -29,6 +29,7 @@ form:
|
||||
|
||||
content:
|
||||
type: markdown
|
||||
showPreview: true
|
||||
validate:
|
||||
type: textarea
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ form:
|
||||
|
||||
content:
|
||||
type: markdown
|
||||
showPreview: true
|
||||
|
||||
uploads:
|
||||
type: pagemedia
|
||||
|
||||
@@ -25,6 +25,7 @@ form:
|
||||
|
||||
content:
|
||||
type: markdown
|
||||
showPreview: true
|
||||
|
||||
uploads:
|
||||
type: pagemedia
|
||||
|
||||
@@ -54,3 +54,32 @@ form:
|
||||
default: 'en'
|
||||
help: PLUGIN_ADMIN.LANGUAGE_HELP
|
||||
|
||||
security:
|
||||
title: Security
|
||||
type: section
|
||||
security: admin.super
|
||||
|
||||
fields:
|
||||
groups:
|
||||
type: selectize
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.GROUPS
|
||||
'@data-options': '\Grav\User\Groups::groups'
|
||||
classes: fancy
|
||||
help: PLUGIN_ADMIN.GROUPS_HELP
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
access.admin:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.ADMIN_ACCESS
|
||||
multiple: false
|
||||
validate:
|
||||
type: array
|
||||
|
||||
access.site:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.SITE_ACCESS
|
||||
multiple: false
|
||||
validate:
|
||||
type: array
|
||||
44
system/blueprints/user/group.yaml
Normal file
44
system/blueprints/user/group.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
title: Group
|
||||
form:
|
||||
validation: loose
|
||||
|
||||
fields:
|
||||
spacer:
|
||||
type: spacer
|
||||
text: '<br>'
|
||||
|
||||
groupname:
|
||||
type: text
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.NAME
|
||||
disabled: true
|
||||
readonly: true
|
||||
|
||||
readableName:
|
||||
type: text
|
||||
size: large
|
||||
label: PLUGIN_ADMIN_PRO.READABLE_NAME
|
||||
|
||||
description:
|
||||
type: text
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.DESCRIPTION
|
||||
|
||||
icon:
|
||||
type: text
|
||||
size: small
|
||||
label: PLUGIN_ADMIN_PRO.ICON
|
||||
|
||||
access.admin:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.ADMIN_ACCESS
|
||||
multiple: false
|
||||
validate:
|
||||
type: array
|
||||
|
||||
access.site:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.SITE_ACCESS
|
||||
multiple: false
|
||||
validate:
|
||||
type: array
|
||||
16
system/blueprints/user/group_new.yaml
Normal file
16
system/blueprints/user/group_new.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
title: PLUGIN_ADMIN_PRO.ADD_GROUP
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
content:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN_PRO.ADD_GROUP
|
||||
|
||||
groupname:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN_PRO.GROUP_NAME
|
||||
help: PLUGIN_ADMIN_PRO.GROUP_NAME_HELP
|
||||
validate:
|
||||
required: true
|
||||
@@ -97,6 +97,7 @@ debugger:
|
||||
images:
|
||||
default_image_quality: 85 # Default image quality to use when resampling images (85%)
|
||||
cache_all: false # Cache all image by default
|
||||
cache_perms: 0755 # Default cache folder perms. Usually 0755 or 0775 depending on setup
|
||||
debug: false # Show an overlay over images indicating the pixel depth of the image when working with retina for example
|
||||
|
||||
media:
|
||||
@@ -108,6 +109,6 @@ media:
|
||||
session:
|
||||
enabled: true # Enable Session support
|
||||
timeout: 1800 # Timeout in seconds
|
||||
name: grav-site # Name prefix of the session cookie
|
||||
name: grav-site # Name prefix of the session cookie. Use alphanumeric, dashes or underscores only. Do not use dots in the session name
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// Some standard defines
|
||||
define('GRAV', true);
|
||||
define('GRAV_VERSION', '1.0.0-rc.5');
|
||||
define('GRAV_VERSION', '1.0.0');
|
||||
define('DS', '/');
|
||||
|
||||
// Directories and Paths
|
||||
|
||||
@@ -95,3 +95,4 @@ NICETIME:
|
||||
FORM:
|
||||
VALIDATION_FAIL: <b>Validation failed:</b>
|
||||
INVALID_INPUT: Invalid input in
|
||||
MISSING_REQUIRED_FIELD: Missing required field:
|
||||
|
||||
42
system/languages/es.yaml
Normal file
42
system/languages/es.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: No se proporcionó fecha
|
||||
BAD_DATE: Fecha erronea
|
||||
AGO: antes
|
||||
FROM_NOW: desde ahora
|
||||
SECOND: segundo
|
||||
MINUTE: minuto
|
||||
HOUR: hora
|
||||
DAY: dia
|
||||
WEEK: semana
|
||||
MONTH: mes
|
||||
YEAR: año
|
||||
DECADE: decada
|
||||
SEC: seg
|
||||
MIN: min
|
||||
HR: hr
|
||||
DAY: dia
|
||||
WK: sem
|
||||
MO: mes
|
||||
YR: yr
|
||||
DEC: dec
|
||||
SECOND_PLURAL: segundos
|
||||
MINUTE_PLURAL: minutos
|
||||
HOUR_PLURAL: horas
|
||||
DAY_PLURAL: días
|
||||
WEEK_PLURAL: semanas
|
||||
MONTH_PLURAL: meses
|
||||
YEAR_PLURAL: años
|
||||
DECADE_PLURAL: decadas
|
||||
SEC_PLURAL: segs
|
||||
MIN_PLURAL: mins
|
||||
HR_PLURAL: hrs
|
||||
DAY_PLURAL: dias
|
||||
WK_PLURAL: sem
|
||||
MO_PLURAL: mes
|
||||
YR_PLURAL: años
|
||||
DEC_PLURAL: decs
|
||||
FORM:
|
||||
VALIDATION_FAIL: <b>Falló la validación. </b>
|
||||
INVALID_INPUT: "Dato inválido en: "
|
||||
MISSING_REQUIRED_FIELD: "Falta el campo requerido: "
|
||||
|
||||
@@ -1,26 +1,60 @@
|
||||
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Erreur : Frontmatter invalide\n\nPath: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
|
||||
INFLECTOR_PLURALS:
|
||||
'/$/': 's'
|
||||
'/(bijou|caillou|chou|genou|hibou|joujou|pou|au|eu|eau)$/': '\1x'
|
||||
'/(bleu|émeu|landau|lieu|pneu|sarrau)$/': '\1s'
|
||||
'/(b|cor|ém|gemm|soupir|trav|vant|vitr)ail$/': '\1aux'
|
||||
'/(s|x|z)$/': '\1'
|
||||
'/ail$/': 'ails'
|
||||
'/al$/': 'aux'
|
||||
'/(quiz)$/i': '\1zes'
|
||||
'/^(ox)$/i': '\1en'
|
||||
'/([m|l])ouse$/i': '\1ice'
|
||||
'/(matr|vert|ind)ix|ex$/i': '\1ices'
|
||||
'/(x|ch|ss|sh)$/i': '\1es'
|
||||
'/([^aeiouy]|qu)ies$/i': '\1y'
|
||||
'/([^aeiouy]|qu)y$/i': '\1ies'
|
||||
'/(hive)$/i': '\1s'
|
||||
'/(?:([^f])fe|([lr])f)$/i': '\1\2ves'
|
||||
'/sis$/i': 'ses'
|
||||
'/([ti])um$/i': '\1a'
|
||||
'/(buffal|tomat)o$/i': '\1oes'
|
||||
'/(bu)s$/i': '\1ses'
|
||||
'/(alias|status)/i': '\1es'
|
||||
'/(octop|vir)us$/i': '\1i'
|
||||
'/(ax|test)is$/i': '\1es'
|
||||
'/s$/i': 's'
|
||||
'/$/': 's'
|
||||
INFLECTOR_SINGULAR:
|
||||
'/(bijou|caillou|chou|genou|hibou|joujou|pou|au|eu|eau)x$/': '\1'
|
||||
'/(b|cor|ém|gemm|soupir|trav|vant|vitr)aux$/': '\1ail'
|
||||
'/(journ|chev)aux$/': '\1al'
|
||||
'/ails$/': 'ail'
|
||||
'/(quiz)zes$/i': '\1'
|
||||
'/(matr)ices$/i': '\1ix'
|
||||
'/(vert|ind)ices$/i': '\1ex'
|
||||
'/^(ox)en/i': '\1'
|
||||
'/(alias|status)es$/i': '\1'
|
||||
'/([octop|vir])i$/i': '\1us'
|
||||
'/(cris|ax|test)es$/i': '\1is'
|
||||
'/(shoe)s$/i': '\1'
|
||||
'/(o)es$/i': '\1'
|
||||
'/(bus)es$/i': '\1'
|
||||
'/([m|l])ice$/i': '\1ouse'
|
||||
'/(x|ch|ss|sh)es$/i': '\1'
|
||||
'/(m)ovies$/i': '\1ovie'
|
||||
'/(s)eries$/i': '\1eries'
|
||||
'/([^aeiouy]|qu)ies$/i': '\1y'
|
||||
'/([lr])ves$/i': '\1f'
|
||||
'/(tive)s$/i': '\1'
|
||||
'/(hive)s$/i': '\1'
|
||||
'/([^f])ves$/i': '\1fe'
|
||||
'/(^analy)ses$/i': '\1sis'
|
||||
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
|
||||
'/([ti])a$/i': '\1um'
|
||||
'/(n)ews$/i': '\1ews'
|
||||
'/s$/i': ''
|
||||
INFLECTOR_UNCOUNTABLE: ['équipment', 'information', 'riz', 'argent', 'espèces', 'séries', 'poisson', 'mouton']
|
||||
INFLECTOR_IRREGULAR:
|
||||
'madame': 'mesdames'
|
||||
'mademoiselle': 'mesdemoiselles'
|
||||
'monsieur': 'messieurs'
|
||||
'person': 'personnes'
|
||||
'man': 'Hommes'
|
||||
'child': 'enfants'
|
||||
'sex': 'sexes'
|
||||
'move': 'déplacemements'
|
||||
INFLECTOR_ORDINALS:
|
||||
'default': 'ème'
|
||||
'first': 'er'
|
||||
'second': 'nd'
|
||||
'third': 'ème'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Aucune date
|
||||
BAD_DATE: Date erronée
|
||||
@@ -48,7 +82,7 @@ NICETIME:
|
||||
DAY_PLURAL: jours
|
||||
WEEK_PLURAL: semaines
|
||||
MONTH_PLURAL: mois
|
||||
YEAR_PLURAL: ans
|
||||
YEAR_PLURAL: années
|
||||
DECADE_PLURAL: décennies
|
||||
SEC_PLURAL: s
|
||||
MIN_PLURAL: m
|
||||
@@ -58,3 +92,7 @@ NICETIME:
|
||||
MO_PLURAL: m
|
||||
YR_PLURAL: a
|
||||
DEC_PLURAL: d
|
||||
FORM:
|
||||
VALIDATION_FAIL: <b>La validation a échoué :</b>
|
||||
INVALID_INPUT: Saisie non valide
|
||||
MISSING_REQUIRED_FIELD: Champ obligatoire manquant :
|
||||
|
||||
@@ -26,12 +26,18 @@ NICETIME:
|
||||
YR: g
|
||||
DEC: des
|
||||
SECOND_PLURAL: sekundi
|
||||
SECOND_PLURAL_MORE_THAN_TWO: sekunde
|
||||
MINUTE_PLURAL: minuta
|
||||
MINUTE_PLURAL_MORE_THAN_TWO: minute
|
||||
HOUR_PLURAL: sati
|
||||
HOUR_PLURAL_MORE_THAN_TWO: sata
|
||||
DAY_PLURAL: dana
|
||||
WEEK_PLURAL: tjedana
|
||||
WEEK_PLURAL_MORE_THAN_TWO: tjedna
|
||||
MONTH_PLURAL: mjeseci
|
||||
MONTH_PLURAL_MORE_THAN_TWO: mjeseca
|
||||
YEAR_PLURAL: godina
|
||||
YEAR_PLURAL_MORE_THAN_TWO: godine
|
||||
DECADE_PLURAL: desetljeća
|
||||
SEC_PLURAL: sek
|
||||
MIN_PLURAL: min
|
||||
|
||||
53
system/languages/hu.yaml
Normal file
53
system/languages/hu.yaml
Normal file
@@ -0,0 +1,53 @@
|
||||
FRONTMATTER_ERROR_PAGE: "---\ncím: %1$s\n---\n\n# Hiba: Érvénytelen Frontmatter\n\nElérési út: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
|
||||
INFLECTOR_IRREGULAR:
|
||||
'person': 'személyek'
|
||||
'man': 'férfiak'
|
||||
'child': 'gyerekek'
|
||||
'sex': 'nemek'
|
||||
'move': 'lépések'
|
||||
INFLECTOR_ORDINALS:
|
||||
'default': '.'
|
||||
'first': '.'
|
||||
'second': '.'
|
||||
'third': '.'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Nincs dátum megadva
|
||||
BAD_DATE: Hibás dátum
|
||||
AGO: elteltével
|
||||
FROM_NOW: mostantól
|
||||
SECOND: másodperc
|
||||
MINUTE: perc
|
||||
HOUR: óra
|
||||
DAY: nap
|
||||
WEEK: hét
|
||||
MONTH: hónap
|
||||
YEAR: év
|
||||
DECADE: évtized
|
||||
SEC: mp
|
||||
MIN: p
|
||||
HR: ó
|
||||
DAY: nap
|
||||
WK: hét
|
||||
MO: hó
|
||||
YR: év
|
||||
DEC: évt
|
||||
SECOND_PLURAL: másodperc
|
||||
MINUTE_PLURAL: perc
|
||||
HOUR_PLURAL: óra
|
||||
DAY_PLURAL: nap
|
||||
WEEK_PLURAL: hét
|
||||
MONTH_PLURAL: hónap
|
||||
YEAR_PLURAL: év
|
||||
DECADE_PLURAL: évtized
|
||||
SEC_PLURAL: mp
|
||||
MIN_PLURAL: perc
|
||||
HR_PLURAL: ó
|
||||
DAY_PLURAL: nap
|
||||
WK_PLURAL: hét
|
||||
MO_PLURAL: hó
|
||||
YR_PLURAL: év
|
||||
DEC_PLURAL: évt
|
||||
FORM:
|
||||
VALIDATION_FAIL: <b>A validáció hibát talált:</b>
|
||||
INVALID_INPUT: Az itt megadott érték érvénytelen:
|
||||
MISSING_REQUIRED_FIELD: Ez a kötelező mező nincs kitöltve:
|
||||
@@ -19,3 +19,7 @@ NICETIME:
|
||||
MONTH_PLURAL: mesi
|
||||
YEAR_PLURAL: anni
|
||||
DECADE_PLURAL: decadi
|
||||
FORM:
|
||||
VALIDATION_FAIL: <b>Validazione fallita:</b>
|
||||
INVALID_INPUT: Input invalido in
|
||||
MISSING_REQUIRED_FIELD: Campo richiesto mancante:
|
||||
|
||||
@@ -203,7 +203,7 @@ class Assets
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function add($asset, $priority = null, $pipeline = null)
|
||||
public function add($asset, $priority = null, $pipeline = true)
|
||||
{
|
||||
// More than one asset
|
||||
if (is_array($asset)) {
|
||||
@@ -243,7 +243,7 @@ class Assets
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addCss($asset, $priority = null, $pipeline = null, $group = null)
|
||||
public function addCss($asset, $priority = null, $pipeline = true, $group = null)
|
||||
{
|
||||
if (is_array($asset)) {
|
||||
foreach ($asset as $a) {
|
||||
@@ -259,16 +259,20 @@ class Assets
|
||||
$asset = $this->buildLocalLink($asset);
|
||||
}
|
||||
|
||||
// Check for existence
|
||||
if ($asset === false) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'asset' => $asset,
|
||||
'priority' => intval($priority ?: 10),
|
||||
'order' => count($this->css),
|
||||
'pipeline' => $pipeline ?: true,
|
||||
'pipeline' => (bool) $pipeline,
|
||||
'group' => $group ?: 'head'
|
||||
];
|
||||
|
||||
// check for dynamic array and merge with defaults
|
||||
$count_args = func_num_args();
|
||||
if (func_num_args() == 2) {
|
||||
$dynamic_arg = func_get_arg(1);
|
||||
if (is_array($dynamic_arg)) {
|
||||
@@ -297,7 +301,7 @@ class Assets
|
||||
* @param string $group name of the group
|
||||
* @return $this
|
||||
*/
|
||||
public function addJs($asset, $priority = null, $pipeline = null, $loading = null, $group = null)
|
||||
public function addJs($asset, $priority = null, $pipeline = true, $loading = null, $group = null)
|
||||
{
|
||||
if (is_array($asset)) {
|
||||
foreach ($asset as $a) {
|
||||
@@ -313,17 +317,21 @@ class Assets
|
||||
$asset = $this->buildLocalLink($asset);
|
||||
}
|
||||
|
||||
// Check for existence
|
||||
if ($asset === false) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'asset' => $asset,
|
||||
'priority' => intval($priority ?: 10),
|
||||
'order' => count($this->js),
|
||||
'pipeline' => $pipeline ?: true,
|
||||
'pipeline' => (bool) $pipeline,
|
||||
'loading' => $loading ?: '',
|
||||
'group' => $group ?: 'head'
|
||||
];
|
||||
|
||||
// check for dynamic array and merge with defaults
|
||||
$count_args = func_num_args();
|
||||
if (func_num_args() == 2) {
|
||||
$dynamic_arg = func_get_arg(1);
|
||||
if (is_array($dynamic_arg)) {
|
||||
@@ -351,7 +359,7 @@ class Assets
|
||||
*
|
||||
* @return \Grav\Common\Assets
|
||||
*/
|
||||
public function addAsyncJs($asset, $priority = null, $pipeline = null, $group = null)
|
||||
public function addAsyncJs($asset, $priority = null, $pipeline = true, $group = null)
|
||||
{
|
||||
return $this->addJs($asset, $priority, $pipeline, 'async', $group);
|
||||
}
|
||||
@@ -368,7 +376,7 @@ class Assets
|
||||
*
|
||||
* @return \Grav\Common\Assets
|
||||
*/
|
||||
public function addDeferJs($asset, $priority = null, $pipeline = null, $group = null)
|
||||
public function addDeferJs($asset, $priority = null, $pipeline = true, $group = null)
|
||||
{
|
||||
return $this->addJs($asset, $priority, $pipeline, 'defer', $group);
|
||||
}
|
||||
@@ -1124,6 +1132,36 @@ class Assets
|
||||
return $this->addDir($directory, self::JS_REGEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state of CSS Pipeline
|
||||
*
|
||||
* @param boolean $value
|
||||
*/
|
||||
public function setCssPipeline($value)
|
||||
{
|
||||
$this->css_pipeline = (bool) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state of JS Pipeline
|
||||
*
|
||||
* @param boolean $value
|
||||
*/
|
||||
public function setJsPipeline($value)
|
||||
{
|
||||
$this->js_pipeline = (bool) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly set's a timestamp for assets
|
||||
*
|
||||
* @param $value
|
||||
*/
|
||||
public function setTimestamp($value)
|
||||
{
|
||||
$this->timestamp = '?'.$value;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return '';
|
||||
|
||||
@@ -38,6 +38,8 @@ class Cache extends Getters
|
||||
*/
|
||||
protected $driver;
|
||||
|
||||
protected $driver_name;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
@@ -110,6 +112,10 @@ class Cache extends Getters
|
||||
|
||||
// Set the cache namespace to our unique key
|
||||
$this->driver->setNamespace($this->key);
|
||||
|
||||
// Dump Cache state
|
||||
$grav['debugger']->addMessage('Cache: [' . ($this->enabled ? 'true' : 'false') . '] Driver: [' . $this->driver_name . ']');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,6 +142,8 @@ class Cache extends Getters
|
||||
$driver_name = $setting;
|
||||
}
|
||||
|
||||
$this->driver_name = $driver_name;
|
||||
|
||||
switch ($driver_name) {
|
||||
case 'apc':
|
||||
$driver = new \Doctrine\Common\Cache\ApcCache();
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use RocketTheme\Toolbox\Blueprints\Blueprints as BaseBlueprints;
|
||||
use RocketTheme\Toolbox\File\PhpFile;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
/**
|
||||
* The Blueprints class contains configuration rules.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Blueprints extends BaseBlueprints
|
||||
{
|
||||
protected $grav;
|
||||
protected $files = [];
|
||||
protected $blueprints;
|
||||
|
||||
public function __construct(array $serialized = null, Grav $grav = null)
|
||||
{
|
||||
parent::__construct($serialized);
|
||||
$this->grav = $grav ?: Grav::instance();
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $this->grav['locator'];
|
||||
|
||||
$blueprints = $locator->findResources('blueprints://config');
|
||||
$plugins = $locator->findResources('plugins://');
|
||||
|
||||
$blueprintFiles = $this->getBlueprintFiles($blueprints, $plugins);
|
||||
|
||||
$this->loadCompiledBlueprints($plugins + $blueprints, $blueprintFiles);
|
||||
}
|
||||
|
||||
protected function loadCompiledBlueprints($blueprints, $blueprintFiles)
|
||||
{
|
||||
$checksum = md5(serialize($blueprints));
|
||||
$filename = CACHE_DIR . 'compiled/blueprints/' . $checksum .'.php';
|
||||
$checksum .= ':'.md5(serialize($blueprintFiles));
|
||||
$class = get_class($this);
|
||||
$file = PhpFile::instance($filename);
|
||||
|
||||
if ($file->exists()) {
|
||||
$cache = $file->exists() ? $file->content() : null;
|
||||
} else {
|
||||
$cache = null;
|
||||
}
|
||||
|
||||
|
||||
// Load real file if cache isn't up to date (or is invalid).
|
||||
if (
|
||||
!is_array($cache)
|
||||
|| empty($cache['checksum'])
|
||||
|| empty($cache['$class'])
|
||||
|| $cache['checksum'] != $checksum
|
||||
|| $cache['@class'] != $class
|
||||
) {
|
||||
// Attempt to lock the file for writing.
|
||||
$file->lock(false);
|
||||
|
||||
// Load blueprints.
|
||||
$this->blueprints = new Blueprints();
|
||||
foreach ($blueprintFiles as $key => $files) {
|
||||
$this->loadBlueprints($key);
|
||||
}
|
||||
|
||||
$cache = [
|
||||
'@class' => $class,
|
||||
'checksum' => $checksum,
|
||||
'files' => $blueprintFiles,
|
||||
'data' => $this->blueprints->toArray()
|
||||
];
|
||||
|
||||
// If compiled file wasn't already locked by another process, save it.
|
||||
if ($file->locked() !== false) {
|
||||
$file->save($cache);
|
||||
$file->unlock();
|
||||
}
|
||||
} else {
|
||||
$this->blueprints = new Blueprints($cache['data']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load global blueprints.
|
||||
*
|
||||
* @param string $key
|
||||
* @param array $files
|
||||
*/
|
||||
public function loadBlueprints($key, array $files = null)
|
||||
{
|
||||
if (is_null($files)) {
|
||||
$files = $this->files[$key];
|
||||
}
|
||||
foreach ($files as $name => $item) {
|
||||
$file = CompiledYamlFile::instance($item['file']);
|
||||
$this->blueprints->embed($name, $file->content(), '/');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all blueprint files (including plugins).
|
||||
*
|
||||
* @param array $blueprints
|
||||
* @param array $plugins
|
||||
* @return array
|
||||
*/
|
||||
protected function getBlueprintFiles(array $blueprints, array $plugins)
|
||||
{
|
||||
$list = [];
|
||||
foreach (array_reverse($plugins) as $folder) {
|
||||
$list += $this->detectPlugins($folder, true);
|
||||
}
|
||||
foreach (array_reverse($blueprints) as $folder) {
|
||||
$list += $this->detectConfig($folder, true);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all plugins with a configuration file and returns last modification time.
|
||||
*
|
||||
* @param string $lookup Location to look up from.
|
||||
* @param bool $blueprints
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectPlugins($lookup = SYSTEM_DIR, $blueprints = false)
|
||||
{
|
||||
$find = $blueprints ? 'blueprints.yaml' : '.yaml';
|
||||
$location = $blueprints ? 'blueprintFiles' : 'configFiles';
|
||||
$path = trim(Folder::getRelativePath($lookup), '/');
|
||||
if (isset($this->{$location}[$path])) {
|
||||
return [$path => $this->{$location}[$path]];
|
||||
}
|
||||
|
||||
$list = [];
|
||||
|
||||
if (is_dir($lookup)) {
|
||||
$iterator = new \DirectoryIterator($lookup);
|
||||
|
||||
/** @var \DirectoryIterator $directory */
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir() || $directory->isDot()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $directory->getBasename();
|
||||
$filename = "{$path}/{$name}/" . ($find && $find[0] != '.' ? $find : $name . $find);
|
||||
|
||||
if (is_file($filename)) {
|
||||
$list["plugins/{$name}"] = ['file' => $filename, 'modified' => filemtime($filename)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->{$location}[$path] = $list;
|
||||
|
||||
return [$path => $list];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all plugins with a configuration file and returns last modification time.
|
||||
*
|
||||
* @param string $lookup Location to look up from.
|
||||
* @param bool $blueprints
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectConfig($lookup = SYSTEM_DIR, $blueprints = false)
|
||||
{
|
||||
$location = $blueprints ? 'blueprintFiles' : 'configFiles';
|
||||
$path = trim(Folder::getRelativePath($lookup), '/');
|
||||
if (isset($this->{$location}[$path])) {
|
||||
return [$path => $this->{$location}[$path]];
|
||||
}
|
||||
|
||||
if (is_dir($lookup)) {
|
||||
// Find all system and user configuration files.
|
||||
$options = [
|
||||
'compare' => 'Filename',
|
||||
'pattern' => '|\.yaml$|',
|
||||
'filters' => [
|
||||
'key' => '|\.yaml$|',
|
||||
'value' => function (\RecursiveDirectoryIterator $file) use ($path) {
|
||||
return ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()];
|
||||
}],
|
||||
'key' => 'SubPathname'
|
||||
];
|
||||
|
||||
$list = Folder::all($lookup, $options);
|
||||
} else {
|
||||
$list = [];
|
||||
}
|
||||
|
||||
$this->{$location}[$path] = $list;
|
||||
|
||||
return [$path => $list];
|
||||
}
|
||||
}
|
||||
236
system/src/Grav/Common/Config/CompiledBase.php
Normal file
236
system/src/Grav/Common/Config/CompiledBase.php
Normal file
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use RocketTheme\Toolbox\File\PhpFile;
|
||||
|
||||
/**
|
||||
* The Compiled base class.
|
||||
*/
|
||||
abstract class CompiledBase
|
||||
{
|
||||
/**
|
||||
* @var int Version number for the compiled file.
|
||||
*/
|
||||
public $version = 1;
|
||||
|
||||
/**
|
||||
* @var string Filename (base name) of the compiled configuration.
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var string|bool Configuration checksum.
|
||||
*/
|
||||
public $checksum;
|
||||
|
||||
/**
|
||||
* @var string Cache folder to be used.
|
||||
*/
|
||||
protected $cacheFolder;
|
||||
|
||||
/**
|
||||
* @var array List of files to load.
|
||||
*/
|
||||
protected $files;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* @var mixed Configuration object.
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* @param string $cacheFolder Cache folder to be used.
|
||||
* @param array $files List of files as returned from ConfigFileFinder class.
|
||||
* @param string $path Base path for the file list.
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function __construct($cacheFolder, array $files, $path)
|
||||
{
|
||||
if (!$cacheFolder) {
|
||||
throw new \BadMethodCallException('Cache folder not defined.');
|
||||
}
|
||||
|
||||
$this->cacheFolder = $cacheFolder;
|
||||
$this->files = $files;
|
||||
$this->path = $path ? rtrim($path, '\\/') . '/' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename for the compiled PHP file.
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function name($name = null)
|
||||
{
|
||||
if (!$this->name) {
|
||||
$this->name = $name ?: md5(json_encode(array_keys($this->files)));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function gets called when cached configuration is saved.
|
||||
*/
|
||||
public function modified() {}
|
||||
|
||||
/**
|
||||
* Load the configuration.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function load()
|
||||
{
|
||||
if ($this->object) {
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
$filename = $this->createFilename();
|
||||
if (!$this->loadCompiledFile($filename) && $this->loadFiles()) {
|
||||
$this->saveCompiledFile($filename);
|
||||
}
|
||||
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns checksum from the configuration files.
|
||||
*
|
||||
* You can set $this->checksum = false to disable this check.
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function checksum()
|
||||
{
|
||||
if (!isset($this->checksum)) {
|
||||
$this->checksum = md5(json_encode($this->files) . $this->version);
|
||||
}
|
||||
|
||||
return $this->checksum;
|
||||
}
|
||||
|
||||
protected function createFilename()
|
||||
{
|
||||
return "{$this->cacheFolder}/{$this->name()->name}.php";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create configuration object.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
abstract protected function createObject(array $data = []);
|
||||
|
||||
/**
|
||||
* Finalize configuration object.
|
||||
*/
|
||||
abstract protected function finalizeObject();
|
||||
|
||||
/**
|
||||
* Load single configuration file and append it to the correct position.
|
||||
*
|
||||
* @param string $name Name of the position.
|
||||
* @param string $filename File to be loaded.
|
||||
*/
|
||||
abstract protected function loadFile($name, $filename);
|
||||
|
||||
/**
|
||||
* Load and join all configuration files.
|
||||
*
|
||||
* @return bool
|
||||
* @internal
|
||||
*/
|
||||
protected function loadFiles()
|
||||
{
|
||||
$this->createObject();
|
||||
|
||||
$list = array_reverse($this->files);
|
||||
foreach ($list as $files) {
|
||||
foreach ($files as $name => $item) {
|
||||
$this->loadFile($name, $this->path . $item['file']);
|
||||
}
|
||||
}
|
||||
|
||||
$this->finalizeObject();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load compiled file.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return bool
|
||||
* @internal
|
||||
*/
|
||||
protected function loadCompiledFile($filename)
|
||||
{
|
||||
if (!file_exists($filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cache = include $filename;
|
||||
if (
|
||||
!is_array($cache)
|
||||
|| !isset($cache['checksum'])
|
||||
|| !isset($cache['data'])
|
||||
|| !isset($cache['@class'])
|
||||
|| $cache['@class'] != get_class($this)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load real file if cache isn't up to date (or is invalid).
|
||||
if ($cache['checksum'] !== $this->checksum()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->createObject($cache['data']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save compiled file.
|
||||
*
|
||||
* @param string $filename
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
protected function saveCompiledFile($filename)
|
||||
{
|
||||
$file = PhpFile::instance($filename);
|
||||
|
||||
// Attempt to lock the file for writing.
|
||||
try {
|
||||
$file->lock(false);
|
||||
} catch (\Exception $e) {
|
||||
// Another process has locked the file; we will check this in a bit.
|
||||
}
|
||||
|
||||
if ($file->locked() === false) {
|
||||
// File was already locked by another process.
|
||||
return;
|
||||
}
|
||||
|
||||
$cache = [
|
||||
'@class' => get_class($this),
|
||||
'timestamp' => time(),
|
||||
'checksum' => $this->checksum(),
|
||||
'files' => $this->files,
|
||||
'data' => $this->object->toArray()
|
||||
];
|
||||
|
||||
$file->save($cache);
|
||||
$file->unlock();
|
||||
$file->free();
|
||||
|
||||
$this->modified();
|
||||
}
|
||||
}
|
||||
49
system/src/Grav/Common/Config/CompiledBlueprints.php
Normal file
49
system/src/Grav/Common/Config/CompiledBlueprints.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use RocketTheme\Toolbox\Blueprints\Blueprints;
|
||||
|
||||
/**
|
||||
* The Compiled Blueprints class.
|
||||
*/
|
||||
class CompiledBlueprints extends CompiledBase
|
||||
{
|
||||
/**
|
||||
* @var int Version number for the compiled file.
|
||||
*/
|
||||
public $version = 1;
|
||||
|
||||
/**
|
||||
* @var Blueprints Blueprints object.
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* Create configuration object.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
protected function createObject(array $data = [])
|
||||
{
|
||||
$this->object = new Blueprints($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize configuration object.
|
||||
*/
|
||||
protected function finalizeObject() {}
|
||||
|
||||
/**
|
||||
* Load single configuration file and append it to the correct position.
|
||||
*
|
||||
* @param string $name Name of the position.
|
||||
* @param string $filename File to be loaded.
|
||||
*/
|
||||
protected function loadFile($name, $filename)
|
||||
{
|
||||
$file = CompiledYamlFile::instance($filename);
|
||||
$this->object->embed($name, $file->content(), '/');
|
||||
$file->free();
|
||||
}
|
||||
}
|
||||
98
system/src/Grav/Common/Config/CompiledConfig.php
Normal file
98
system/src/Grav/Common/Config/CompiledConfig.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
|
||||
/**
|
||||
* The Compiled Configuration class.
|
||||
*/
|
||||
class CompiledConfig extends CompiledBase
|
||||
{
|
||||
/**
|
||||
* @var int Version number for the compiled file.
|
||||
*/
|
||||
public $version = 1;
|
||||
|
||||
/**
|
||||
* @var Config Configuration object.
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* @var callable Blueprints loader.
|
||||
*/
|
||||
protected $callable;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $withDefaults;
|
||||
|
||||
/**
|
||||
* Set blueprints for the configuration.
|
||||
*
|
||||
* @param callable $blueprints
|
||||
* @return $this
|
||||
*/
|
||||
public function setBlueprints(callable $blueprints)
|
||||
{
|
||||
$this->callable = $blueprints;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $withDefaults
|
||||
* @return mixed
|
||||
*/
|
||||
public function load($withDefaults = false)
|
||||
{
|
||||
$this->withDefaults = $withDefaults;
|
||||
|
||||
return parent::load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create configuration object.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
protected function createObject(array $data = [])
|
||||
{
|
||||
if ($this->withDefaults && empty($data) && is_callable($this->callable)) {
|
||||
$blueprints = $this->callable;
|
||||
$data = $blueprints()->getDefaults();
|
||||
}
|
||||
|
||||
$this->object = new Config($data, $this->callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize configuration object.
|
||||
*/
|
||||
protected function finalizeObject()
|
||||
{
|
||||
$this->object->checksum($this->checksum());
|
||||
}
|
||||
|
||||
/**
|
||||
* Function gets called when cached configuration is saved.
|
||||
*/
|
||||
public function modified()
|
||||
{
|
||||
$this->object->modified(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load single configuration file and append it to the correct position.
|
||||
*
|
||||
* @param string $name Name of the position.
|
||||
* @param string $filename File to be loaded.
|
||||
*/
|
||||
protected function loadFile($name, $filename)
|
||||
{
|
||||
$file = CompiledYamlFile::instance($filename);
|
||||
$this->object->join($name, $file->content(), '/');
|
||||
$file->free();
|
||||
}
|
||||
}
|
||||
64
system/src/Grav/Common/Config/CompiledLanguages.php
Normal file
64
system/src/Grav/Common/Config/CompiledLanguages.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
|
||||
/**
|
||||
* The Compiled Languages class.
|
||||
*/
|
||||
class CompiledLanguages extends CompiledBase
|
||||
{
|
||||
/**
|
||||
* @var int Version number for the compiled file.
|
||||
*/
|
||||
public $version = 1;
|
||||
|
||||
/**
|
||||
* @var Languages Configuration object.
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* Create configuration object.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
protected function createObject(array $data = [])
|
||||
{
|
||||
$this->object = new Languages($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize configuration object.
|
||||
*/
|
||||
protected function finalizeObject()
|
||||
{
|
||||
$this->object->checksum($this->checksum());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function gets called when cached configuration is saved.
|
||||
*/
|
||||
public function modified()
|
||||
{
|
||||
$this->object->modified(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load single configuration file and append it to the correct position.
|
||||
*
|
||||
* @param string $name Name of the position.
|
||||
* @param string $filename File to be loaded.
|
||||
*/
|
||||
protected function loadFile($name, $filename)
|
||||
{
|
||||
$file = CompiledYamlFile::instance($filename);
|
||||
if (preg_match('|languages\.yaml$|', $filename)) {
|
||||
$this->object->mergeRecursive($file->content());
|
||||
} else {
|
||||
$this->object->join($name, $file->content(), '/');
|
||||
}
|
||||
$file->free();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\Debugger;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Data\Data;
|
||||
use RocketTheme\Toolbox\Blueprints\Blueprints;
|
||||
use RocketTheme\Toolbox\File\PhpFile;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
use Grav\Common\Service\ConfigServiceProvider;
|
||||
|
||||
/**
|
||||
* The Config class contains configuration information.
|
||||
@@ -16,471 +14,84 @@ use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
*/
|
||||
class Config extends Data
|
||||
{
|
||||
protected $grav;
|
||||
protected $streams = [
|
||||
'system' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['system'],
|
||||
]
|
||||
],
|
||||
'user' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user'],
|
||||
]
|
||||
],
|
||||
'asset' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['assets'],
|
||||
]
|
||||
],
|
||||
'blueprints' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://blueprints', 'system/blueprints'],
|
||||
]
|
||||
],
|
||||
'config' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://config', 'system/config'],
|
||||
]
|
||||
],
|
||||
'plugins' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://plugins'],
|
||||
]
|
||||
],
|
||||
'plugin' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://plugins'],
|
||||
]
|
||||
],
|
||||
'themes' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://themes'],
|
||||
]
|
||||
],
|
||||
'languages' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://languages', 'system/languages'],
|
||||
]
|
||||
],
|
||||
'cache' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
'' => ['cache'],
|
||||
'images' => ['images']
|
||||
]
|
||||
],
|
||||
'log' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
'' => ['logs']
|
||||
]
|
||||
],
|
||||
'backup' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
'' => ['backup']
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
protected $setup = [];
|
||||
|
||||
protected $blueprintFiles = [];
|
||||
protected $configFiles = [];
|
||||
protected $languageFiles = [];
|
||||
protected $checksum;
|
||||
protected $timestamp;
|
||||
|
||||
protected $configLookup;
|
||||
protected $blueprintLookup;
|
||||
protected $pluginLookup;
|
||||
protected $languagesLookup;
|
||||
|
||||
protected $finder;
|
||||
protected $environment;
|
||||
protected $messages = [];
|
||||
|
||||
protected $languages;
|
||||
|
||||
public function __construct(array $setup = array(), Grav $grav = null, $environment = null)
|
||||
{
|
||||
$this->grav = $grav ?: Grav::instance();
|
||||
$this->finder = new ConfigFinder;
|
||||
$this->environment = $environment ?: 'localhost';
|
||||
$this->messages[] = 'Environment Name: ' . $this->environment;
|
||||
|
||||
// Make sure that
|
||||
if (!isset($setup['streams']['schemes'])) {
|
||||
$setup['streams']['schemes'] = [];
|
||||
}
|
||||
$setup['streams']['schemes'] += $this->streams;
|
||||
|
||||
$setup = $this->autoDetectEnvironmentConfig($setup);
|
||||
|
||||
$this->setup = $setup;
|
||||
parent::__construct($setup);
|
||||
|
||||
$this->check();
|
||||
}
|
||||
protected $modified = false;
|
||||
|
||||
public function key()
|
||||
{
|
||||
return $this->checksum();
|
||||
}
|
||||
|
||||
public function reload()
|
||||
public function checksum($checksum = null)
|
||||
{
|
||||
$this->items = $this->setup;
|
||||
$this->check();
|
||||
$this->init();
|
||||
$this->debug();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function check()
|
||||
{
|
||||
$streams = isset($this->items['streams']['schemes']) ? $this->items['streams']['schemes'] : null;
|
||||
if (!is_array($streams)) {
|
||||
throw new \InvalidArgumentException('Configuration is missing streams.schemes!');
|
||||
}
|
||||
$diff = array_keys(array_diff_key($this->streams, $streams));
|
||||
if ($diff) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf('Configuration is missing keys %s from streams.schemes!', implode(', ', $diff))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function debug()
|
||||
{
|
||||
foreach ($this->messages as $message) {
|
||||
$this->grav['debugger']->addMessage($message);
|
||||
}
|
||||
$this->messages = [];
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $this->grav['locator'];
|
||||
|
||||
$this->configLookup = $locator->findResources('config://');
|
||||
$this->blueprintLookup = $locator->findResources('blueprints://config');
|
||||
$this->pluginLookup = $locator->findResources('plugins://');
|
||||
|
||||
|
||||
$this->loadCompiledBlueprints($this->blueprintLookup, $this->pluginLookup, 'master');
|
||||
$this->loadCompiledConfig($this->configLookup, $this->pluginLookup, 'master');
|
||||
|
||||
// process languages if supported
|
||||
if ($this->get('system.languages.translations', true)) {
|
||||
$this->languagesLookup = $locator->findResources('languages://');
|
||||
$this->loadCompiledLanguages($this->languagesLookup, $this->pluginLookup, 'master');
|
||||
}
|
||||
|
||||
$this->initializeLocator($locator);
|
||||
}
|
||||
|
||||
public function checksum()
|
||||
{
|
||||
if (empty($this->checksum)) {
|
||||
$checkBlueprints = $this->get('system.cache.check.blueprints', false);
|
||||
$checkLanguages = $this->get('system.cache.check.languages', false);
|
||||
$checkConfig = $this->get('system.cache.check.config', true);
|
||||
$checkSystem = $this->get('system.cache.check.system', true);
|
||||
|
||||
if (!$checkBlueprints && !$checkLanguages && !$checkConfig && !$checkSystem) {
|
||||
$this->messages[] = 'Skip configuration timestamp check.';
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate checksum according to the configuration settings.
|
||||
if (!$checkConfig) {
|
||||
// Just check changes in system.yaml files and ignore all the other files.
|
||||
$cc = $checkSystem ? $this->finder->locateConfigFile($this->configLookup, 'system') : [];
|
||||
} else {
|
||||
// Check changes in all configuration files.
|
||||
$cc = $this->finder->locateConfigFiles($this->configLookup, $this->pluginLookup);
|
||||
}
|
||||
|
||||
if ($checkBlueprints) {
|
||||
$cb = $this->finder->locateBlueprintFiles($this->blueprintLookup, $this->pluginLookup);
|
||||
} else {
|
||||
$cb = [];
|
||||
}
|
||||
|
||||
if ($checkLanguages) {
|
||||
$cl = $this->finder->locateLanguageFiles($this->languagesLookup, $this->pluginLookup);
|
||||
} else {
|
||||
$cl = [];
|
||||
}
|
||||
|
||||
$this->checksum = md5(json_encode([$cc, $cb, $cl]));
|
||||
if ($checksum !== null) {
|
||||
$this->checksum = $checksum;
|
||||
}
|
||||
|
||||
return $this->checksum;
|
||||
}
|
||||
|
||||
protected function autoDetectEnvironmentConfig($items)
|
||||
public function modified($modified = null)
|
||||
{
|
||||
$environment = $this->environment;
|
||||
$env_stream = 'user://'.$environment.'/config';
|
||||
|
||||
if (file_exists(USER_DIR.$environment.'/config')) {
|
||||
array_unshift($items['streams']['schemes']['config']['prefixes'][''], $env_stream);
|
||||
if ($modified !== null) {
|
||||
$this->modified = $modified;
|
||||
}
|
||||
|
||||
return $items;
|
||||
return $this->modified;
|
||||
}
|
||||
|
||||
protected function loadCompiledBlueprints($blueprints, $plugins, $filename = null)
|
||||
public function reload()
|
||||
{
|
||||
$checksum = md5(json_encode($blueprints));
|
||||
$filename = $filename
|
||||
? CACHE_DIR . 'compiled/blueprints/' . $filename . '-' . $this->environment . '.php'
|
||||
: CACHE_DIR . 'compiled/blueprints/' . $checksum . '-' . $this->environment . '.php';
|
||||
$file = PhpFile::instance($filename);
|
||||
$cache = $file->exists() ? $file->content() : null;
|
||||
$blueprintFiles = $this->finder->locateBlueprintFiles($blueprints, $plugins);
|
||||
$checksum .= ':'.md5(json_encode($blueprintFiles));
|
||||
$class = get_class($this);
|
||||
$grav = Grav::instance();
|
||||
|
||||
// Load real file if cache isn't up to date (or is invalid).
|
||||
if (
|
||||
!is_array($cache)
|
||||
|| !isset($cache['checksum'])
|
||||
|| !isset($cache['@class'])
|
||||
|| $cache['checksum'] != $checksum
|
||||
|| $cache['@class'] != $class
|
||||
) {
|
||||
// Attempt to lock the file for writing.
|
||||
$file->lock(false);
|
||||
// Load new configuration.
|
||||
$config = ConfigServiceProvider::load($grav);
|
||||
|
||||
// Load blueprints.
|
||||
$this->blueprints = new Blueprints;
|
||||
foreach ($blueprintFiles as $files) {
|
||||
$this->loadBlueprintFiles($files);
|
||||
}
|
||||
/** @var Debugger $debugger */
|
||||
$debugger = $grav['debugger'];
|
||||
|
||||
$cache = [
|
||||
'@class' => $class,
|
||||
'checksum' => $checksum,
|
||||
'files' => $blueprintFiles,
|
||||
'data' => $this->blueprints->toArray()
|
||||
];
|
||||
// If compiled file wasn't already locked by another process, save it.
|
||||
if ($file->locked() !== false) {
|
||||
$this->messages[] = 'Saving compiled blueprints.';
|
||||
$file->save($cache);
|
||||
$file->unlock();
|
||||
}
|
||||
} else {
|
||||
$this->blueprints = new Blueprints($cache['data']);
|
||||
if ($config->modified()) {
|
||||
// Update current configuration.
|
||||
$this->items = $config->toArray();
|
||||
$this->checksum($config->checksum());
|
||||
$this->modified(true);
|
||||
|
||||
$debugger->addMessage('Configuration was changed and saved.');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function debug()
|
||||
{
|
||||
/** @var Debugger $debugger */
|
||||
$debugger = Grav::instance()['debugger'];
|
||||
|
||||
$debugger->addMessage('Environment Name: ' . $this->environment);
|
||||
if ($this->modified()) {
|
||||
$debugger->addMessage('Configuration reloaded and cached.');
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadCompiledConfig($configs, $plugins, $filename = null)
|
||||
public function init()
|
||||
{
|
||||
$checksum = md5(json_encode($configs));
|
||||
$filename = $filename
|
||||
? CACHE_DIR . 'compiled/config/' . $filename . '-' . $this->environment . '.php'
|
||||
: CACHE_DIR . 'compiled/config/' . $checksum . '-' . $this->environment . '.php';
|
||||
$file = PhpFile::instance($filename);
|
||||
$cache = $file->exists() ? $file->content() : null;
|
||||
$class = get_class($this);
|
||||
$checksum = $this->checksum();
|
||||
|
||||
if (
|
||||
!is_array($cache)
|
||||
|| !isset($cache['checksum'])
|
||||
|| !isset($cache['@class'])
|
||||
|| $cache['@class'] != $class
|
||||
) {
|
||||
$this->messages[] = 'No cached configuration, compiling new configuration..';
|
||||
} else if ($cache['checksum'] !== $checksum) {
|
||||
$this->messages[] = 'Configuration checksum mismatch, reloading configuration..';
|
||||
} else {
|
||||
$this->messages[] = 'Configuration checksum matches, using cached version.';
|
||||
|
||||
$this->items = $cache['data'];
|
||||
return;
|
||||
}
|
||||
|
||||
$configFiles = $this->finder->locateConfigFiles($configs, $plugins);
|
||||
|
||||
// Attempt to lock the file for writing.
|
||||
$file->lock(false);
|
||||
|
||||
// Load configuration.
|
||||
foreach ($configFiles as $files) {
|
||||
$this->loadConfigFiles($files);
|
||||
}
|
||||
$cache = [
|
||||
'@class' => $class,
|
||||
'timestamp' => time(),
|
||||
'checksum' => $checksum,
|
||||
'data' => $this->toArray()
|
||||
];
|
||||
|
||||
// If compiled file wasn't already locked by another process, save it.
|
||||
if ($file->locked() !== false) {
|
||||
$this->messages[] = 'Saving compiled configuration.';
|
||||
$file->save($cache);
|
||||
$file->unlock();
|
||||
}
|
||||
|
||||
$this->items = $cache['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $languages
|
||||
* @param $plugins
|
||||
* @param null $filename
|
||||
*/
|
||||
protected function loadCompiledLanguages($languages, $plugins, $filename = null)
|
||||
{
|
||||
$checksum = md5(json_encode($languages));
|
||||
$filename = $filename
|
||||
? CACHE_DIR . 'compiled/languages/' . $filename . '-' . $this->environment . '.php'
|
||||
: CACHE_DIR . 'compiled/languages/' . $checksum . '-' . $this->environment . '.php';
|
||||
$file = PhpFile::instance($filename);
|
||||
$cache = $file->exists() ? $file->content() : null;
|
||||
$languageFiles = $this->finder->locateLanguageFiles($languages, $plugins);
|
||||
$checksum .= ':' . md5(json_encode($languageFiles));
|
||||
$class = get_class($this);
|
||||
|
||||
// Load real file if cache isn't up to date (or is invalid).
|
||||
if (
|
||||
!is_array($cache)
|
||||
|| !isset($cache['checksum'])
|
||||
|| !isset($cache['@class'])
|
||||
|| $cache['checksum'] != $checksum
|
||||
|| $cache['@class'] != $class
|
||||
) {
|
||||
// Attempt to lock the file for writing.
|
||||
$file->lock(false);
|
||||
|
||||
// Load languages.
|
||||
$this->languages = new Languages;
|
||||
$pluginPaths = str_ireplace(GRAV_ROOT . '/', '', array_reverse($plugins));
|
||||
foreach ($pluginPaths as $path) {
|
||||
if (isset($languageFiles[$path])) {
|
||||
foreach ((array) $languageFiles[$path] as $plugin => $item) {
|
||||
$lang_file = CompiledYamlFile::instance($item['file']);
|
||||
$content = $lang_file->content();
|
||||
$this->languages->mergeRecursive($content);
|
||||
}
|
||||
unset($languageFiles[$path]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($languageFiles as $location) {
|
||||
foreach ($location as $lang => $item) {
|
||||
$lang_file = CompiledYamlFile::instance($item['file']);
|
||||
$content = $lang_file->content();
|
||||
$this->languages->join($lang, $content, '/');
|
||||
}
|
||||
}
|
||||
|
||||
$cache = [
|
||||
'@class' => $class,
|
||||
'checksum' => $checksum,
|
||||
'files' => $languageFiles,
|
||||
'data' => $this->languages->toArray()
|
||||
];
|
||||
// If compiled file wasn't already locked by another process, save it.
|
||||
if ($file->locked() !== false) {
|
||||
$this->messages[] = 'Saving compiled languages.';
|
||||
$file->save($cache);
|
||||
$file->unlock();
|
||||
}
|
||||
} else {
|
||||
$this->languages = new Languages($cache['data']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load blueprints.
|
||||
*
|
||||
* @param array $files
|
||||
*/
|
||||
public function loadBlueprintFiles(array $files)
|
||||
{
|
||||
foreach ($files as $name => $item) {
|
||||
$file = CompiledYamlFile::instance($item['file']);
|
||||
$this->blueprints->embed($name, $file->content(), '/');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load configuration.
|
||||
*
|
||||
* @param array $files
|
||||
*/
|
||||
public function loadConfigFiles(array $files)
|
||||
{
|
||||
foreach ($files as $name => $item) {
|
||||
$file = CompiledYamlFile::instance($item['file']);
|
||||
$this->join($name, $file->content(), '/');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize resource locator by using the configuration.
|
||||
*
|
||||
* @param UniformResourceLocator $locator
|
||||
*/
|
||||
public function initializeLocator(UniformResourceLocator $locator)
|
||||
{
|
||||
$locator->reset();
|
||||
|
||||
$schemes = (array) $this->get('streams.schemes', []);
|
||||
|
||||
foreach ($schemes as $scheme => $config) {
|
||||
if (isset($config['paths'])) {
|
||||
$locator->addPath($scheme, '', $config['paths']);
|
||||
}
|
||||
if (isset($config['prefixes'])) {
|
||||
foreach ($config['prefixes'] as $prefix => $paths) {
|
||||
$locator->addPath($scheme, $prefix, $paths);
|
||||
}
|
||||
$setup = Grav::instance()['setup']->toArray();
|
||||
foreach ($setup as $key => $value) {
|
||||
if ($key === 'streams' || !is_array($value)) {
|
||||
// Optimized as streams and simple values are fully defined in setup.
|
||||
$this->items[$key] = $value;
|
||||
} else {
|
||||
$this->joinDefaults($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available streams and their types from the configuration.
|
||||
*
|
||||
* @return array
|
||||
* @return mixed
|
||||
* @deprecated
|
||||
*/
|
||||
public function getStreams()
|
||||
{
|
||||
$schemes = [];
|
||||
foreach ((array) $this->get('streams.schemes') as $scheme => $config) {
|
||||
$type = !empty($config['type']) ? $config['type'] : 'ReadOnlyStream';
|
||||
if ($type[0] != '\\') {
|
||||
$type = '\\RocketTheme\\Toolbox\\StreamWrapper\\' . $type;
|
||||
}
|
||||
|
||||
$schemes[$scheme] = $type;
|
||||
}
|
||||
|
||||
return $schemes;
|
||||
}
|
||||
|
||||
public function getLanguages()
|
||||
{
|
||||
return $this->languages;
|
||||
return Grav::instance()['languages'];
|
||||
}
|
||||
}
|
||||
|
||||
258
system/src/Grav/Common/Config/ConfigFileFinder.php
Normal file
258
system/src/Grav/Common/Config/ConfigFileFinder.php
Normal file
@@ -0,0 +1,258 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
|
||||
/**
|
||||
* The Configuration & Blueprints Finder class.
|
||||
*/
|
||||
class ConfigFileFinder
|
||||
{
|
||||
protected $base = '';
|
||||
|
||||
/**
|
||||
* @param string $base
|
||||
* @return $this
|
||||
*/
|
||||
public function setBase($base)
|
||||
{
|
||||
$this->base = $base ? "{$base}/" : '';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all locations for all the files with a timestamp.
|
||||
*
|
||||
* @param array $paths List of folders to look from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
*/
|
||||
public function locateFiles(array $paths, $pattern = '|\.yaml$|', $levels = -1)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($paths as $folder) {
|
||||
$list += $this->detectRecursive($folder, $pattern, $levels);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all locations for all the files with a timestamp.
|
||||
*
|
||||
* @param array $paths List of folders to look from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
*/
|
||||
public function getFiles(array $paths, $pattern = '|\.yaml$|', $levels = -1)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($paths as $folder) {
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
$files = $this->detectRecursive($folder, $pattern, $levels);
|
||||
|
||||
$list += $files[trim($path, '/')];
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all paths for all the files with a timestamp.
|
||||
*
|
||||
* @param array $paths List of folders to look from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
*/
|
||||
public function listFiles(array $paths, $pattern = '|\.yaml$|', $levels = -1)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($paths as $folder) {
|
||||
$list = array_merge_recursive($list, $this->detectAll($folder, $pattern, $levels));
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find filename from a list of folders.
|
||||
*
|
||||
* Note: Only finds the last override.
|
||||
*
|
||||
* @param string $filename
|
||||
* @param array $folders
|
||||
* @return array
|
||||
*/
|
||||
public function locateFileInFolder($filename, array $folders)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($folders as $folder) {
|
||||
$list += $this->detectInFolder($folder, $filename);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find filename from a list of folders.
|
||||
*
|
||||
* @param array $folders
|
||||
* @param string $filename
|
||||
* @return array
|
||||
*/
|
||||
public function locateInFolders(array $folders, $filename = null)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($folders as $folder) {
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
$list[$path] = $this->detectInFolder($folder, $filename);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all existing locations for a single file with a timestamp.
|
||||
*
|
||||
* @param array $paths Filesystem paths to look up from.
|
||||
* @param string $name Configuration file to be located.
|
||||
* @param string $ext File extension (optional, defaults to .yaml).
|
||||
* @return array
|
||||
*/
|
||||
public function locateFile(array $paths, $name, $ext = '.yaml')
|
||||
{
|
||||
$filename = preg_replace('|[.\/]+|', '/', $name) . $ext;
|
||||
|
||||
$list = [];
|
||||
foreach ($paths as $folder) {
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
if (is_file("{$folder}/{$filename}")) {
|
||||
$modified = filemtime("{$folder}/{$filename}");
|
||||
} else {
|
||||
$modified = 0;
|
||||
}
|
||||
$basename = $this->base . $name;
|
||||
$list[$path] = [$basename => ['file' => "{$path}/{$filename}", 'modified' => $modified]];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all directories with a configuration file and returns them with last modification time.
|
||||
*
|
||||
* @param string $folder Location to look up from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectRecursive($folder, $pattern, $levels)
|
||||
{
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
if (is_dir($folder)) {
|
||||
// Find all system and user configuration files.
|
||||
$options = [
|
||||
'levels' => $levels,
|
||||
'compare' => 'Filename',
|
||||
'pattern' => $pattern,
|
||||
'filters' => [
|
||||
'pre-key' => $this->base,
|
||||
'key' => $pattern,
|
||||
'value' => function (\RecursiveDirectoryIterator $file) use ($path) {
|
||||
return ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()];
|
||||
}
|
||||
],
|
||||
'key' => 'SubPathname'
|
||||
];
|
||||
|
||||
$list = Folder::all($folder, $options);
|
||||
|
||||
ksort($list);
|
||||
} else {
|
||||
$list = [];
|
||||
}
|
||||
|
||||
return [$path => $list];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all directories with the lookup file and returns them with last modification time.
|
||||
*
|
||||
* @param string $folder Location to look up from.
|
||||
* @param string $lookup Filename to be located (defaults to directory name).
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectInFolder($folder, $lookup = null)
|
||||
{
|
||||
$folder = rtrim($folder, '/');
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
$base = $path === $folder ? '' : ($path ? substr($folder, 0, -strlen($path)) : $folder . '/');
|
||||
|
||||
$list = [];
|
||||
|
||||
if (is_dir($folder)) {
|
||||
$iterator = new \DirectoryIterator($folder);
|
||||
|
||||
/** @var \DirectoryIterator $directory */
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir() || $directory->isDot()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $directory->getBasename();
|
||||
$find = ($lookup ?: $name) . '.yaml';
|
||||
$filename = "{$path}/{$name}/{$find}";
|
||||
|
||||
if (file_exists($base . $filename)) {
|
||||
$basename = $this->base . $name;
|
||||
$list[$basename] = ['file' => $filename, 'modified' => filemtime($base . $filename)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all plugins with a configuration file and returns them with last modification time.
|
||||
*
|
||||
* @param string $folder Location to look up from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectAll($folder, $pattern, $levels)
|
||||
{
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
if (is_dir($folder)) {
|
||||
// Find all system and user configuration files.
|
||||
$options = [
|
||||
'levels' => $levels,
|
||||
'compare' => 'Filename',
|
||||
'pattern' => $pattern,
|
||||
'filters' => [
|
||||
'pre-key' => $this->base,
|
||||
'key' => $pattern,
|
||||
'value' => function (\RecursiveDirectoryIterator $file) use ($path) {
|
||||
return ["{$path}/{$file->getSubPathname()}" => $file->getMTime()];
|
||||
}
|
||||
],
|
||||
'key' => 'SubPathname'
|
||||
];
|
||||
|
||||
$list = Folder::all($folder, $options);
|
||||
|
||||
ksort($list);
|
||||
} else {
|
||||
$list = [];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
|
||||
/**
|
||||
* The Configuration Finder class.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class ConfigFinder
|
||||
{
|
||||
/**
|
||||
* Get all locations for blueprint files (including plugins).
|
||||
*
|
||||
* @param array $blueprints
|
||||
* @param array $plugins
|
||||
* @return array
|
||||
*/
|
||||
public function locateBlueprintFiles(array $blueprints, array $plugins)
|
||||
{
|
||||
$list = [];
|
||||
foreach (array_reverse($plugins) as $folder) {
|
||||
$list += $this->detectInFolder($folder, 'blueprints');
|
||||
}
|
||||
foreach (array_reverse($blueprints) as $folder) {
|
||||
$list += $this->detectRecursive($folder);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all locations for configuration files (including plugins).
|
||||
*
|
||||
* @param array $configs
|
||||
* @param array $plugins
|
||||
* @return array
|
||||
*/
|
||||
public function locateConfigFiles(array $configs, array $plugins)
|
||||
{
|
||||
$list = [];
|
||||
foreach (array_reverse($plugins) as $folder) {
|
||||
$list += $this->detectInFolder($folder);
|
||||
}
|
||||
foreach (array_reverse($configs) as $folder) {
|
||||
$list += $this->detectRecursive($folder);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function locateLanguageFiles(array $languages, array $plugins)
|
||||
{
|
||||
$list = [];
|
||||
foreach (array_reverse($plugins) as $folder) {
|
||||
$list += $this->detectLanguagesInFolder($folder, 'languages');
|
||||
}
|
||||
foreach (array_reverse($languages) as $folder) {
|
||||
$list += $this->detectRecursive($folder);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all locations for a single configuration file.
|
||||
*
|
||||
* @param array $folders Locations to look up from.
|
||||
* @param string $name Filename to be located.
|
||||
* @return array
|
||||
*/
|
||||
public function locateConfigFile(array $folders, $name)
|
||||
{
|
||||
$filename = "{$name}.yaml";
|
||||
|
||||
$list = [];
|
||||
foreach ($folders as $folder) {
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
if (is_file("{$folder}/{$filename}")) {
|
||||
$modified = filemtime("{$folder}/{$filename}");
|
||||
} else {
|
||||
$modified = 0;
|
||||
}
|
||||
$list[$path] = [$name => ['file' => "{$path}/{$filename}", 'modified' => $modified]];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all plugins with a configuration file and returns them with last modification time.
|
||||
*
|
||||
* @param string $folder Location to look up from.
|
||||
* @param string $lookup Filename to be located.
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectInFolder($folder, $lookup = null)
|
||||
{
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
$list = [];
|
||||
|
||||
if (is_dir($folder)) {
|
||||
$iterator = new \FilesystemIterator($folder);
|
||||
|
||||
/** @var \DirectoryIterator $directory */
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $directory->getBasename();
|
||||
$find = ($lookup ?: $name) . '.yaml';
|
||||
$filename = "{$path}/{$name}/$find";
|
||||
|
||||
if (file_exists($filename)) {
|
||||
$list["plugins/{$name}"] = ['file' => $filename, 'modified' => filemtime($filename)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [$path => $list];
|
||||
}
|
||||
|
||||
protected function detectLanguagesInFolder($folder, $lookup = null)
|
||||
{
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
$list = [];
|
||||
|
||||
if (is_dir($folder)) {
|
||||
$iterator = new \FilesystemIterator($folder);
|
||||
|
||||
/** @var \DirectoryIterator $directory */
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $directory->getBasename();
|
||||
$find = ($lookup ?: $name) . '.yaml';
|
||||
$filename = "{$path}/{$name}/$find";
|
||||
|
||||
if (file_exists($filename)) {
|
||||
$list[$name] = ['file' => $filename, 'modified' => filemtime($filename)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [$path => $list];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all plugins with a configuration file and returns them with last modification time.
|
||||
*
|
||||
* @param string $folder Location to look up from.
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectRecursive($folder)
|
||||
{
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
if (is_dir($folder)) {
|
||||
// Find all system and user configuration files.
|
||||
$options = [
|
||||
'compare' => 'Filename',
|
||||
'pattern' => '|\.yaml$|',
|
||||
'filters' => [
|
||||
'key' => '|\.yaml$|',
|
||||
'value' => function (\RecursiveDirectoryIterator $file) use ($path) {
|
||||
return ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()];
|
||||
}
|
||||
],
|
||||
'key' => 'SubPathname'
|
||||
];
|
||||
|
||||
$list = Folder::all($folder, $options);
|
||||
} else {
|
||||
$list = [];
|
||||
}
|
||||
|
||||
return [$path => $list];
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,23 @@ use Grav\Common\Data\Data;
|
||||
*/
|
||||
class Languages extends Data
|
||||
{
|
||||
public function checksum($checksum = null)
|
||||
{
|
||||
if ($checksum !== null) {
|
||||
$this->checksum = $checksum;
|
||||
}
|
||||
|
||||
return $this->checksum;
|
||||
}
|
||||
|
||||
public function modified($modified = null)
|
||||
{
|
||||
if ($modified !== null) {
|
||||
$this->modified = $modified;
|
||||
}
|
||||
|
||||
return $this->modified;
|
||||
}
|
||||
|
||||
public function reformat()
|
||||
{
|
||||
|
||||
254
system/src/Grav/Common/Config/Setup.php
Normal file
254
system/src/Grav/Common/Config/Setup.php
Normal file
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\Utils;
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
/**
|
||||
* The Config class contains configuration information.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Setup extends Data
|
||||
{
|
||||
protected $streams = [
|
||||
'system' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['system'],
|
||||
]
|
||||
],
|
||||
'user' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user'],
|
||||
]
|
||||
],
|
||||
'environment' => [
|
||||
'type' => 'ReadOnlyStream'
|
||||
// If not defined, environment will be set up in the constructor.
|
||||
],
|
||||
'asset' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['assets'],
|
||||
]
|
||||
],
|
||||
'blueprints' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['environment://blueprints', 'user://blueprints', 'system/blueprints'],
|
||||
]
|
||||
],
|
||||
'config' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['environment://config', 'user://config', 'system/config'],
|
||||
]
|
||||
],
|
||||
'plugins' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://plugins'],
|
||||
]
|
||||
],
|
||||
'plugin' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://plugins'],
|
||||
]
|
||||
],
|
||||
'themes' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://themes'],
|
||||
]
|
||||
],
|
||||
'languages' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['environment://languages', 'user://languages', 'system/languages'],
|
||||
]
|
||||
],
|
||||
'cache' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
'' => ['cache'],
|
||||
'images' => ['images']
|
||||
]
|
||||
],
|
||||
'log' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
'' => ['logs']
|
||||
]
|
||||
],
|
||||
'backup' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
'' => ['backup']
|
||||
]
|
||||
],
|
||||
'image' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://images', 'system://images']
|
||||
]
|
||||
],
|
||||
'page' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://pages']
|
||||
]
|
||||
],
|
||||
'account' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://accounts']
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
public function __construct($container)
|
||||
{
|
||||
$environment = $container['uri']->environment();
|
||||
if (!$environment) {
|
||||
$environment = 'localhost';
|
||||
}
|
||||
|
||||
// Pre-load setup.php which contains our initial configuration.
|
||||
// Configuration may contain dynamic parts, which is why we need to always load it.
|
||||
$file = GRAV_ROOT . '/setup.php';
|
||||
$setup = is_file($file) ? (array) include $file : [];
|
||||
|
||||
// Add default streams defined in beginning of the class.
|
||||
if (!isset($setup['streams']['schemes'])) {
|
||||
$setup['streams']['schemes'] = [];
|
||||
}
|
||||
$setup['streams']['schemes'] += $this->streams;
|
||||
|
||||
// Initialize class.
|
||||
parent::__construct($setup);
|
||||
|
||||
// Set up environment.
|
||||
$this->def('environment', $environment);
|
||||
$this->def('streams.schemes.environment.prefixes', ['' => ["user://{$this->environment}"]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$locator = new UniformResourceLocator(GRAV_ROOT);
|
||||
$files = [];
|
||||
|
||||
$guard = 5;
|
||||
do {
|
||||
$check = $files;
|
||||
$this->initializeLocator($locator);
|
||||
$files = $locator->findResources('config://streams.yaml');
|
||||
|
||||
if ($check === $files) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Update streams.
|
||||
foreach ($files as $path) {
|
||||
$file = CompiledYamlFile::instance($path);
|
||||
$content = $file->content();
|
||||
if (!empty($content['schemes'])) {
|
||||
$this->items['streams']['schemes'] = $content['schemes'] + $this->items['streams']['schemes'];
|
||||
}
|
||||
}
|
||||
} while (--$guard);
|
||||
|
||||
if (!$guard) {
|
||||
throw new \RuntimeException('Setup: Configuration reload loop detected!');
|
||||
}
|
||||
|
||||
// Make sure we have valid setup.
|
||||
$this->check($locator);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize resource locator by using the configuration.
|
||||
*
|
||||
* @param UniformResourceLocator $locator
|
||||
*/
|
||||
public function initializeLocator(UniformResourceLocator $locator)
|
||||
{
|
||||
$locator->reset();
|
||||
|
||||
$schemes = (array) $this->get('streams.schemes', []);
|
||||
|
||||
foreach ($schemes as $scheme => $config) {
|
||||
if (isset($config['paths'])) {
|
||||
$locator->addPath($scheme, '', $config['paths']);
|
||||
}
|
||||
if (isset($config['prefixes'])) {
|
||||
foreach ($config['prefixes'] as $prefix => $paths) {
|
||||
$locator->addPath($scheme, $prefix, $paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available streams and their types from the configuration.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getStreams()
|
||||
{
|
||||
$schemes = [];
|
||||
foreach ((array) $this->get('streams.schemes') as $scheme => $config) {
|
||||
$type = !empty($config['type']) ? $config['type'] : 'ReadOnlyStream';
|
||||
if ($type[0] != '\\') {
|
||||
$type = '\\RocketTheme\\Toolbox\\StreamWrapper\\' . $type;
|
||||
}
|
||||
|
||||
$schemes[$scheme] = $type;
|
||||
}
|
||||
|
||||
return $schemes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UniformResourceLocator $locator
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function check(UniformResourceLocator $locator)
|
||||
{
|
||||
$streams = isset($this->items['streams']['schemes']) ? $this->items['streams']['schemes'] : null;
|
||||
if (!is_array($streams)) {
|
||||
throw new \InvalidArgumentException('Configuration is missing streams.schemes!');
|
||||
}
|
||||
$diff = array_keys(array_diff_key($this->streams, $streams));
|
||||
if ($diff) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf('Configuration is missing keys %s from streams.schemes!', implode(', ', $diff))
|
||||
);
|
||||
}
|
||||
|
||||
if (!$locator->findResource('environment://config', true)) {
|
||||
// If environment does not have its own directory, remove it from the lookup.
|
||||
$this->set('streams.schemes.environment.prefixes', ['config' => []]);
|
||||
$this->initializeLocator($locator);
|
||||
}
|
||||
|
||||
// Create security.yaml if it doesn't exist.
|
||||
$filename = $locator->findResource('config://security.yaml', true, true);
|
||||
$file = YamlFile::instance($filename);
|
||||
if (!$file->exists()) {
|
||||
$file->save(['salt' => Utils::generateRandomString(14)]);
|
||||
$file->free();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
|
||||
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
|
||||
|
||||
/**
|
||||
* Blueprint handles the inside logic of blueprints.
|
||||
@@ -10,9 +12,9 @@ use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Blueprint
|
||||
class Blueprint implements \ArrayAccess, ExportInterface
|
||||
{
|
||||
use Export, DataMutatorTrait, GravTrait;
|
||||
use Export, NestedArrayAccessWithGetters, GravTrait;
|
||||
|
||||
public $name;
|
||||
|
||||
@@ -240,9 +242,6 @@ class Blueprint
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
if (is_array($field) && count($field) == 1 && reset($field) == '') {
|
||||
continue;
|
||||
}
|
||||
$field = Validation::filter($field, $rule);
|
||||
} elseif (is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
@@ -312,91 +311,105 @@ class Blueprint
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all field definitions from the blueprints.
|
||||
*
|
||||
* @param array $fields
|
||||
* @param array $params
|
||||
* @param string $prefix
|
||||
* @param array $current
|
||||
* @internal
|
||||
*/
|
||||
protected function parseFormFields(array &$fields, $params, $prefix, array &$current)
|
||||
{
|
||||
// Go though all the fields in current level.
|
||||
foreach ($fields as $key => &$field) {
|
||||
$current[$key] = &$field;
|
||||
// Set name from the array key.
|
||||
$field['name'] = $prefix . $key;
|
||||
$field += $params;
|
||||
* Gets all field definitions from the blueprints.
|
||||
*
|
||||
* @param array $fields
|
||||
* @param array $params
|
||||
* @param string $prefix
|
||||
* @param array $current
|
||||
* @internal
|
||||
*/
|
||||
protected function parseFormFields(array &$fields, $params, $prefix, array &$current)
|
||||
{
|
||||
// Go though all the fields in current level.
|
||||
foreach ($fields as $key => &$field) {
|
||||
$current[$key] = &$field;
|
||||
// Set name from the array key.
|
||||
$field['name'] = $prefix . $key;
|
||||
$field += $params;
|
||||
|
||||
if (isset($field['fields']) && (!isset($field['type']) || $field['type'] !== 'list')) {
|
||||
// Recursively get all the nested fields.
|
||||
$newParams = array_intersect_key($this->filter, $field);
|
||||
$this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']);
|
||||
} else if ($field['type'] !== 'ignore') {
|
||||
// Add rule.
|
||||
if (isset($field['fields']) && (!isset($field['type']) || $field['type'] !== 'list')) {
|
||||
// Recursively get all the nested fields.
|
||||
$newParams = array_intersect_key($this->filter, $field);
|
||||
$this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']);
|
||||
} else if ($field['type'] !== 'ignore') {
|
||||
$this->rules[$prefix . $key] = &$field;
|
||||
$this->addProperty($prefix . $key);
|
||||
|
||||
foreach ($field as $name => $value) {
|
||||
// Support nested blueprints.
|
||||
if ($this->context && $name == '@import') {
|
||||
$values = (array) $value;
|
||||
if (!isset($field['fields'])) {
|
||||
$field['fields'] = array();
|
||||
}
|
||||
foreach ($values as $bname) {
|
||||
$b = $this->context->get($bname);
|
||||
$field['fields'] = array_merge($field['fields'], $b->fields());
|
||||
}
|
||||
}
|
||||
|
||||
// Support for callable data values.
|
||||
elseif (substr($name, 0, 6) == '@data-') {
|
||||
$property = substr($name, 6);
|
||||
if (is_array($value)) {
|
||||
$func = array_shift($value);
|
||||
} else {
|
||||
$func = $value;
|
||||
$value = array();
|
||||
}
|
||||
list($o, $f) = preg_split('/::/', $func);
|
||||
if (!$f && function_exists($o)) {
|
||||
$data = call_user_func_array($o, $value);
|
||||
} elseif ($f && method_exists($o, $f)) {
|
||||
$data = call_user_func_array(array($o, $f), $value);
|
||||
}
|
||||
|
||||
// If function returns a value,
|
||||
if (isset($data)) {
|
||||
if (isset($field[$property]) && is_array($field[$property]) && is_array($data)) {
|
||||
// Combine field and @data-field together.
|
||||
$field[$property] += $data;
|
||||
} else {
|
||||
// Or create/replace field with @data-field.
|
||||
$field[$property] = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elseif (substr($name, 0, 8) == '@config-') {
|
||||
$property = substr($name, 8);
|
||||
$default = isset($field[$property]) ? $field[$property] : null;
|
||||
$config = self::getGrav()['config']->get($value, $default);
|
||||
|
||||
if (!is_null($config)) {
|
||||
$field[$property] = $config;
|
||||
}
|
||||
if ($field['type'] === 'list') {
|
||||
// we loop through list to get the actual field
|
||||
foreach($field['fields'] as $subName => &$subField) {
|
||||
$this->parseFormField($subField);
|
||||
}
|
||||
} else {
|
||||
$this->parseFormField($field);
|
||||
}
|
||||
|
||||
// Initialize predefined validation rule.
|
||||
if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') {
|
||||
$field['validate'] += $this->getRule($field['validate']['rule']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Parses individual field definition
|
||||
*
|
||||
* @param array $field
|
||||
* @internal
|
||||
*/
|
||||
protected function parseFormField(&$field) {
|
||||
foreach ($field as $name => $value) {
|
||||
// Support nested blueprints.
|
||||
if ($this->context && $name == '@import') {
|
||||
$values = (array) $value;
|
||||
if (!isset($field['fields'])) {
|
||||
$field['fields'] = array();
|
||||
}
|
||||
foreach ($values as $bname) {
|
||||
$b = $this->context->get($bname);
|
||||
$field['fields'] = array_merge($field['fields'], $b->fields());
|
||||
}
|
||||
}
|
||||
|
||||
// Support for callable data values.
|
||||
elseif (substr($name, 0, 6) == '@data-') {
|
||||
$property = substr($name, 6);
|
||||
if (is_array($value)) {
|
||||
$func = array_shift($value);
|
||||
} else {
|
||||
$func = $value;
|
||||
$value = array();
|
||||
}
|
||||
list($o, $f) = preg_split('/::/', $func);
|
||||
if (!$f && function_exists($o)) {
|
||||
$data = call_user_func_array($o, $value);
|
||||
} elseif ($f && method_exists($o, $f)) {
|
||||
$data = call_user_func_array(array($o, $f), $value);
|
||||
}
|
||||
|
||||
// If function returns a value,
|
||||
if (isset($data)) {
|
||||
if (isset($field[$property]) && is_array($field[$property]) && is_array($data)) {
|
||||
// Combine field and @data-field together.
|
||||
$field[$property] += $data;
|
||||
} else {
|
||||
// Or create/replace field with @data-field.
|
||||
$field[$property] = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elseif (substr($name, 0, 8) == '@config-') {
|
||||
$property = substr($name, 8);
|
||||
$default = isset($field[$property]) ? $field[$property] : null;
|
||||
$config = self::getGrav()['config']->get($value, $default);
|
||||
|
||||
if (!is_null($config)) {
|
||||
$field[$property] = $config;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add property to the definition.
|
||||
@@ -452,7 +465,9 @@ class Blueprint
|
||||
&& $field['validate']['required'] === true
|
||||
&& empty($data[$name])) {
|
||||
$value = isset($field['label']) ? $field['label'] : $field['name'];
|
||||
throw new \RuntimeException("Missing required field: {$value}");
|
||||
$language = self::getGrav()['language'];
|
||||
$message = sprintf($language->translate('FORM.MISSING_REQUIRED_FIELD', null, true) . ' %s', $value);
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use RocketTheme\Toolbox\ArrayTraits\ArrayAccessWithGetters;
|
||||
use RocketTheme\Toolbox\ArrayTraits\Countable;
|
||||
use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
|
||||
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
|
||||
use RocketTheme\Toolbox\Blueprints\Blueprints;
|
||||
use RocketTheme\Toolbox\File\File;
|
||||
use RocketTheme\Toolbox\File\FileInterface;
|
||||
|
||||
@@ -13,9 +15,9 @@ use RocketTheme\Toolbox\File\FileInterface;
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Data implements DataInterface
|
||||
class Data implements DataInterface, \ArrayAccess, \Countable, ExportInterface
|
||||
{
|
||||
use ArrayAccessWithGetters, Countable, Export, DataMutatorTrait;
|
||||
use NestedArrayAccessWithGetters, Countable, Export;
|
||||
|
||||
protected $gettersVariable = 'items';
|
||||
protected $items;
|
||||
@@ -32,12 +34,11 @@ class Data implements DataInterface
|
||||
|
||||
/**
|
||||
* @param array $items
|
||||
* @param Blueprint $blueprints
|
||||
* @param Blueprint|callable $blueprints
|
||||
*/
|
||||
public function __construct(array $items = array(), Blueprint $blueprints = null)
|
||||
public function __construct(array $items = array(), $blueprints = null)
|
||||
{
|
||||
$this->items = $items;
|
||||
|
||||
$this->blueprints = $blueprints;
|
||||
}
|
||||
|
||||
@@ -57,126 +58,150 @@ class Data implements DataInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $data->def('this.is.my.nested.variable', 'default');
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $default Default value (or null).
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
*/
|
||||
public function def($name, $default = null, $separator = '.')
|
||||
{
|
||||
$this->set($name, $this->get($name, $default, $separator), $separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join two values together by using blueprints if available.
|
||||
* Join nested values together by using blueprints.
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $value Value to be joined.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return $this
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function join($name, $value, $separator = '.')
|
||||
{
|
||||
$old = $this->get($name, null, $separator);
|
||||
if ($old === null) {
|
||||
// Variable does not exist yet: just use the incoming value.
|
||||
} elseif ($this->blueprints) {
|
||||
// Blueprints: join values by using blueprints.
|
||||
$value = $this->blueprints->mergeData($old, $value, $name, $separator);
|
||||
} else {
|
||||
// No blueprints: replace existing top level variables with the new ones.
|
||||
$value = array_merge($old, $value);
|
||||
if ($old !== null) {
|
||||
if (!is_array($old)) {
|
||||
throw new \RuntimeException('Value ' . $old);
|
||||
}
|
||||
if (is_object($value)) {
|
||||
$value = (array) $value;
|
||||
} elseif (!is_array($value)) {
|
||||
throw new \RuntimeException('Value ' . $value);
|
||||
}
|
||||
$value = $this->blueprints()->mergeData($old, $value, $name, $separator);
|
||||
}
|
||||
|
||||
$this->set($name, $value, $separator);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join two values together by using blueprints if available.
|
||||
* Get nested structure containing default values defined in the blueprints.
|
||||
*
|
||||
* Fields without default value are ignored in the list.
|
||||
|
||||
* @return array
|
||||
*/
|
||||
public function getDefaults()
|
||||
{
|
||||
return $this->blueprints()->getDefaults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default values by using blueprints.
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $value Value to be joined.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return $this
|
||||
*/
|
||||
public function joinDefaults($name, $value, $separator = '.')
|
||||
{
|
||||
if (is_object($value)) {
|
||||
$value = (array) $value;
|
||||
}
|
||||
$old = $this->get($name, null, $separator);
|
||||
if ($old === null) {
|
||||
// Variable does not exist yet: just use the incoming value.
|
||||
} elseif ($this->blueprints) {
|
||||
// Blueprints: join values by using blueprints.
|
||||
$value = $this->blueprints->mergeData($value, $old, $name, $separator);
|
||||
} else {
|
||||
// No blueprints: replace existing top level variables with the new ones.
|
||||
$value = array_merge($value, $old);
|
||||
if ($old !== null) {
|
||||
$value = $this->blueprints()->mergeData($value, $old, $name, $separator);
|
||||
}
|
||||
|
||||
$this->set($name, $value, $separator);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value from the configuration and join it with given data.
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param array $value Value to be joined.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function getJoined($name, $value, $separator = '.')
|
||||
{
|
||||
if (is_object($value)) {
|
||||
$value = (array) $value;
|
||||
} elseif (!is_array($value)) {
|
||||
throw new \RuntimeException('Value ' . $value);
|
||||
}
|
||||
|
||||
$old = $this->get($name, null, $separator);
|
||||
|
||||
if ($old === null) {
|
||||
// No value set; no need to join data.
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (!is_array($old)) {
|
||||
throw new \RuntimeException('Value ' . $old);
|
||||
}
|
||||
|
||||
// Return joined data.
|
||||
return $this->blueprints()->mergeData($old, $value, $name, $separator);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merge two sets of data together.
|
||||
* Merge two configurations together.
|
||||
*
|
||||
* @param array $data
|
||||
* @return void
|
||||
* @return $this
|
||||
*/
|
||||
public function merge(array $data)
|
||||
{
|
||||
if ($this->blueprints) {
|
||||
$this->items = $this->blueprints->mergeData($this->items, $data);
|
||||
} else {
|
||||
$this->items = array_merge($this->items, $data);
|
||||
}
|
||||
$this->items = $this->blueprints()->mergeData($this->items, $data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add default data to the set.
|
||||
* Set default values to the configuration if variables were not set.
|
||||
*
|
||||
* @param array $data
|
||||
* @return void
|
||||
* @return $this
|
||||
*/
|
||||
public function setDefaults(array $data)
|
||||
{
|
||||
if ($this->blueprints) {
|
||||
$this->items = $this->blueprints->mergeData($data, $this->items);
|
||||
} else {
|
||||
$this->items = array_merge($data, $this->items);
|
||||
}
|
||||
}
|
||||
$this->items = $this->blueprints()->mergeData($data, $this->items);
|
||||
|
||||
/**
|
||||
* Return blueprints.
|
||||
*
|
||||
* @return Blueprint
|
||||
*/
|
||||
public function blueprints()
|
||||
{
|
||||
return $this->blueprints;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate by blueprints.
|
||||
*
|
||||
* @return $this
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
if ($this->blueprints) {
|
||||
$this->blueprints->validate($this->items);
|
||||
}
|
||||
$this->blueprints()->validate($this->items);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* Filter all items by using blueprints.
|
||||
*/
|
||||
public function filter()
|
||||
{
|
||||
if ($this->blueprints) {
|
||||
$this->items = $this->blueprints->filter($this->items);
|
||||
}
|
||||
$this->items = $this->blueprints()->filter($this->items);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,7 +211,24 @@ class Data implements DataInterface
|
||||
*/
|
||||
public function extra()
|
||||
{
|
||||
return $this->blueprints ? $this->blueprints->extra($this->items) : array();
|
||||
return $this->blueprints()->extra($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return blueprints.
|
||||
*
|
||||
* @return Blueprints
|
||||
*/
|
||||
public function blueprints()
|
||||
{
|
||||
if (!$this->blueprints){
|
||||
$this->blueprints = new Blueprints;
|
||||
} elseif (is_callable($this->blueprints)) {
|
||||
// Lazy load blueprints.
|
||||
$blueprints = $this->blueprints;
|
||||
$this->blueprints = $blueprints();
|
||||
}
|
||||
return $this->blueprints;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
trait DataMutatorTrait
|
||||
{
|
||||
|
||||
/**
|
||||
* Get value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $value = $data->get('this.is.my.nested.variable');
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $default Default value (or null).
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return mixed Value.
|
||||
*/
|
||||
public function get($name, $default = null, $separator = '.')
|
||||
{
|
||||
$path = explode($separator, $name);
|
||||
$current = $this->items;
|
||||
foreach ($path as $field) {
|
||||
if (is_object($current) && isset($current->{$field})) {
|
||||
$current = $current->{$field};
|
||||
} elseif (is_array($current) && isset($current[$field])) {
|
||||
$current = $current[$field];
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
return $current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $value = $data->set('this.is.my.nested.variable', true);
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $value New value.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
*/
|
||||
public function set($name, $value, $separator = '.')
|
||||
{
|
||||
$path = explode($separator, $name);
|
||||
$current = &$this->items;
|
||||
foreach ($path as $field) {
|
||||
if (is_object($current)) {
|
||||
// Handle objects.
|
||||
if (!isset($current->{$field})) {
|
||||
$current->{$field} = array();
|
||||
}
|
||||
$current = &$current->{$field};
|
||||
} else {
|
||||
// Handle arrays and scalars.
|
||||
if (!is_array($current)) {
|
||||
$current = array($field => array());
|
||||
} elseif (!isset($current[$field])) {
|
||||
$current[$field] = array();
|
||||
}
|
||||
$current = &$current[$field];
|
||||
}
|
||||
}
|
||||
|
||||
$current = $value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,6 +31,11 @@ class Validation
|
||||
return;
|
||||
}
|
||||
|
||||
// special case for files, value is never empty and errors with code 4 instead
|
||||
if (empty($validate['required']) && $field['type'] == 'file' && (isset($value['error']) && ($value['error'] == UPLOAD_ERR_NO_FILE || in_array(UPLOAD_ERR_NO_FILE, $value['error'])))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get language class
|
||||
$language = self::getGrav()['language'];
|
||||
|
||||
@@ -38,7 +43,7 @@ class Validation
|
||||
$type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type'];
|
||||
$method = 'type'.strtr($type, '-', '_');
|
||||
$name = ucfirst(isset($field['label']) ? $field['label'] : $field['name']);
|
||||
$message = (string) isset($field['validate']['message']) ? $field['validate']['message'] : $language->translate('FORM.INVALID_INPUT', null, true) . ' "' . $language->translate($name) . '"';
|
||||
$message = (string) isset($field['validate']['message']) ? $language->translate($field['validate']['message']) : $language->translate('FORM.INVALID_INPUT', null, true) . ' "' . $language->translate($name) . '"';
|
||||
|
||||
if (method_exists(__CLASS__, $method)) {
|
||||
$success = self::$method($value, $validate, $field);
|
||||
@@ -78,6 +83,11 @@ class Validation
|
||||
return null;
|
||||
}
|
||||
|
||||
// special case for files, value is never empty and errors with code 4 instead
|
||||
if (empty($validate['required']) && $field['type'] == 'file' && (isset($value['error']) && ($value['error'] == UPLOAD_ERR_NO_FILE || in_array(UPLOAD_ERR_NO_FILE, $value['error'])))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if this is a YAML field, simply parse it and return the value
|
||||
if (isset($field['yaml']) && $field['yaml'] === true) {
|
||||
try {
|
||||
@@ -258,6 +268,24 @@ class Validation
|
||||
return self::typeArray((array) $value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom input: file
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeFile($value, array $params, array $field)
|
||||
{
|
||||
return self::typeArray((array) $value, $params, $field);
|
||||
}
|
||||
|
||||
protected static function filterFile($value, array $params, array $field)
|
||||
{
|
||||
return (array) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: select
|
||||
*
|
||||
@@ -592,7 +620,7 @@ class Validation
|
||||
if (is_string($value)) {
|
||||
$value = trim($value);
|
||||
}
|
||||
|
||||
|
||||
return (bool) $params !== true || !empty($value);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,11 @@ trait CompiledFile
|
||||
|| $cache['filename'] != $this->filename
|
||||
) {
|
||||
// Attempt to lock the file for writing.
|
||||
$file->lock(false);
|
||||
try {
|
||||
$file->lock(false);
|
||||
} catch (\Exception $e) {
|
||||
// Another process has locked the file; we will check this in a bit.
|
||||
}
|
||||
|
||||
// Decode RAW file into compiled array.
|
||||
$data = (array) $this->decode($this->raw());
|
||||
@@ -64,6 +68,7 @@ trait CompiledFile
|
||||
$file->unlock();
|
||||
}
|
||||
}
|
||||
$file->free();
|
||||
|
||||
$this->content = $cache['data'];
|
||||
}
|
||||
|
||||
@@ -19,12 +19,12 @@ abstract class Folder
|
||||
{
|
||||
$last_modified = 0;
|
||||
|
||||
$dirItr = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$filterItr = new RecursiveFolderFilterIterator($dirItr);
|
||||
$itr = new \RecursiveIteratorIterator($filterItr, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$filter = new RecursiveFolderFilterIterator($directory);
|
||||
$iterator = new \RecursiveIteratorIterator($filter, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
|
||||
/** @var \RecursiveDirectoryIterator $file */
|
||||
foreach ($itr as $dir) {
|
||||
foreach ($iterator as $dir) {
|
||||
$dir_modified = $dir->getMTime();
|
||||
if ($dir_modified > $last_modified) {
|
||||
$last_modified = $dir_modified;
|
||||
@@ -46,12 +46,12 @@ abstract class Folder
|
||||
{
|
||||
$last_modified = 0;
|
||||
|
||||
$dirItr = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$itrItr = new \RecursiveIteratorIterator($dirItr, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$itr = new \RegexIterator($itrItr, '/^.+\.'.$extensions.'$/i');
|
||||
$directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$recursive = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$iterator = new \RegexIterator($recursive, '/^.+\.'.$extensions.'$/i');
|
||||
|
||||
/** @var \RecursiveDirectoryIterator $file */
|
||||
foreach ($itr as $filepath => $file) {
|
||||
foreach ($iterator as $filepath => $file) {
|
||||
$file_modified = $file->getMTime();
|
||||
if ($file_modified > $last_modified) {
|
||||
$last_modified = $file_modified;
|
||||
@@ -64,8 +64,8 @@ abstract class Folder
|
||||
/**
|
||||
* Get relative path between target and base path. If path isn't relative, return full path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param mixed|string $base
|
||||
* @param string $path
|
||||
* @param string $base
|
||||
* @return string
|
||||
*/
|
||||
public static function getRelativePath($path, $base = GRAV_ROOT)
|
||||
@@ -81,6 +81,43 @@ abstract class Folder
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get relative path between target and base path. If path isn't relative, return full path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $base
|
||||
* @return string
|
||||
*/
|
||||
public static function getRelativePathDotDot($path, $base)
|
||||
{
|
||||
$base = preg_replace('![\\\/]+!', '/', $base);
|
||||
$path = preg_replace('![\\\/]+!', '/', $path);
|
||||
|
||||
if ($path === $base) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$baseParts = explode('/', isset($base[0]) && '/' === $base[0] ? substr($base, 1) : $base);
|
||||
$pathParts = explode('/', isset($path[0]) && '/' === $path[0] ? substr($path, 1) : $path);
|
||||
|
||||
array_pop($baseParts);
|
||||
$lastPart = array_pop($pathParts);
|
||||
foreach ($baseParts as $i => $directory) {
|
||||
if (isset($pathParts[$i]) && $pathParts[$i] === $directory) {
|
||||
unset($baseParts[$i], $pathParts[$i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$pathParts[] = $lastPart;
|
||||
$path = str_repeat('../', count($baseParts)) . implode('/', $pathParts);
|
||||
|
||||
return '' === $path
|
||||
|| '/' === $path[0]
|
||||
|| false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
|
||||
? "./$path" : $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift first directory out of the path.
|
||||
*
|
||||
@@ -96,8 +133,6 @@ abstract class Folder
|
||||
return $result ?: null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return recursive list of all files and directories under given path.
|
||||
*
|
||||
@@ -116,13 +151,17 @@ abstract class Folder
|
||||
$pattern = isset($params['pattern']) ? $params['pattern'] : null;
|
||||
$filters = isset($params['filters']) ? $params['filters'] : null;
|
||||
$recursive = isset($params['recursive']) ? $params['recursive'] : true;
|
||||
$levels = isset($params['levels']) ? $params['levels'] : -1;
|
||||
$key = isset($params['key']) ? 'get' . $params['key'] : null;
|
||||
$value = isset($params['value']) ? 'get' . $params['value'] : ($recursive ? 'getSubPathname' : 'getFilename');
|
||||
$folders = isset($params['folders']) ? $params['folders'] : true;
|
||||
$files = isset($params['files']) ? $params['files'] : true;
|
||||
|
||||
if ($recursive) {
|
||||
$directory = new \RecursiveDirectoryIterator($path,
|
||||
\RecursiveDirectoryIterator::SKIP_DOTS + \FilesystemIterator::UNIX_PATHS + \FilesystemIterator::CURRENT_AS_SELF);
|
||||
$iterator = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$iterator->setMaxDepth(max($levels, -1));
|
||||
} else {
|
||||
$iterator = new \FilesystemIterator($path);
|
||||
}
|
||||
@@ -131,6 +170,16 @@ abstract class Folder
|
||||
|
||||
/** @var \RecursiveDirectoryIterator $file */
|
||||
foreach ($iterator as $file) {
|
||||
// Ignore hidden files.
|
||||
if ($file->getFilename()[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
if (!$folders && $file->isDir()) {
|
||||
continue;
|
||||
}
|
||||
if (!$files && $file->isFile()) {
|
||||
continue;
|
||||
}
|
||||
if ($compare && $pattern && !preg_match($pattern, $file->{$compare}())) {
|
||||
continue;
|
||||
}
|
||||
@@ -138,7 +187,8 @@ abstract class Folder
|
||||
$filePath = $file->{$value}();
|
||||
if ($filters) {
|
||||
if (isset($filters['key'])) {
|
||||
$fileKey = preg_replace($filters['key'], '', $fileKey);
|
||||
$pre = !empty($filters['pre-key']) ? $filters['pre-key'] : '';
|
||||
$fileKey = $pre . preg_replace($filters['key'], '', $fileKey);
|
||||
}
|
||||
if (isset($filters['value'])) {
|
||||
$filter = $filters['value'];
|
||||
@@ -146,12 +196,12 @@ abstract class Folder
|
||||
$filePath = call_user_func($filter, $file);
|
||||
} else {
|
||||
$filePath = preg_replace($filter, '', $filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($fileKey !== null) {
|
||||
$results[$fileKey] = $filePath;
|
||||
$results[$fileKey] = $filePath;
|
||||
} else {
|
||||
$results[] = $filePath;
|
||||
}
|
||||
@@ -163,11 +213,12 @@ abstract class Folder
|
||||
/**
|
||||
* Recursively copy directory in filesystem.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @param string $ignore Ignore files matching pattern (regular expression).
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function copy($source, $target)
|
||||
public static function copy($source, $target, $ignore = null)
|
||||
{
|
||||
$source = rtrim($source, '\\/');
|
||||
$target = rtrim($target, '\\/');
|
||||
@@ -177,19 +228,24 @@ abstract class Folder
|
||||
}
|
||||
|
||||
// Make sure that path to the target exists before copying.
|
||||
self::mkdir($target);
|
||||
self::create($target);
|
||||
|
||||
$success = true;
|
||||
|
||||
// Go through all sub-directories and copy everything.
|
||||
$files = self::all($source);
|
||||
foreach ($files as $file) {
|
||||
if ($ignore && preg_match($ignore, $file)) {
|
||||
continue;
|
||||
}
|
||||
$src = $source .'/'. $file;
|
||||
$dst = $target .'/'. $file;
|
||||
|
||||
if (is_dir($src)) {
|
||||
// Create current directory.
|
||||
$success &= @mkdir($dst);
|
||||
// Create current directory (if it doesn't exist).
|
||||
if (!is_dir($dst)) {
|
||||
$success &= @mkdir($dst, 0777, true);
|
||||
}
|
||||
} else {
|
||||
// Or copy current file.
|
||||
$success &= @copy($src, $dst);
|
||||
@@ -208,8 +264,8 @@ abstract class Folder
|
||||
/**
|
||||
* Move directory in filesystem.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function move($source, $target)
|
||||
@@ -218,8 +274,13 @@ abstract class Folder
|
||||
throw new \RuntimeException('Cannot move non-existing folder.');
|
||||
}
|
||||
|
||||
// Don't do anything if the source is the same as the new target
|
||||
if ($source == $target) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure that path to the target exists before moving.
|
||||
self::mkdir(dirname($target));
|
||||
self::create(dirname($target));
|
||||
|
||||
// Just rename the directory.
|
||||
$success = @rename($source, $target);
|
||||
@@ -238,16 +299,16 @@ abstract class Folder
|
||||
* Recursively delete directory from filesystem.
|
||||
*
|
||||
* @param string $target
|
||||
* @throws \RuntimeException
|
||||
* @param bool $include_target
|
||||
* @return bool
|
||||
*/
|
||||
public static function delete($target)
|
||||
public static function delete($target, $include_target = true)
|
||||
{
|
||||
if (!is_dir($target)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
$success = self::doDelete($target);
|
||||
$success = self::doDelete($target, $include_target);
|
||||
|
||||
if (!$success) {
|
||||
$error = error_get_last();
|
||||
@@ -255,16 +316,31 @@ abstract class Folder
|
||||
}
|
||||
|
||||
// Make sure that the change will be detected when caching.
|
||||
@touch(dirname($target));
|
||||
if ($include_target) {
|
||||
@touch(dirname($target));
|
||||
} else {
|
||||
@touch($target);
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $folder
|
||||
* @param string $folder
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
public static function mkdir($folder)
|
||||
{
|
||||
self::create($folder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $folder
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
public static function create($folder)
|
||||
{
|
||||
if (is_dir($folder)) {
|
||||
return;
|
||||
@@ -320,10 +396,11 @@ abstract class Folder
|
||||
|
||||
/**
|
||||
* @param string $folder
|
||||
* @param bool $include_target
|
||||
* @return bool
|
||||
* @internal
|
||||
*/
|
||||
protected static function doDelete($folder)
|
||||
protected static function doDelete($folder, $include_target = true)
|
||||
{
|
||||
// Special case for symbolic links.
|
||||
if (is_link($folder)) {
|
||||
@@ -338,16 +415,16 @@ abstract class Folder
|
||||
/** @var \DirectoryIterator $fileinfo */
|
||||
foreach ($files as $fileinfo) {
|
||||
if ($fileinfo->isDir()) {
|
||||
if (false === rmdir($fileinfo->getRealPath())) {
|
||||
if (false === @rmdir($fileinfo->getRealPath())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (false === unlink($fileinfo->getRealPath())) {
|
||||
if (false === @unlink($fileinfo->getRealPath())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rmdir($folder);
|
||||
return $include_target ? @rmdir($folder) : true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ class Grav extends AbstractPackageCollection
|
||||
|
||||
$diffLog = [];
|
||||
foreach ($this->data['changelog'] as $version => $changelog) {
|
||||
preg_match("/[\d\.]+/", $version, $cleanVersion);
|
||||
preg_match("/[\w-\.]+/", $version, $cleanVersion);
|
||||
|
||||
if (!$cleanVersion || version_compare($diff, $cleanVersion[0], ">=")) { continue; }
|
||||
|
||||
|
||||
@@ -78,10 +78,12 @@ class Response
|
||||
throw new \RuntimeException('Could not start an HTTP request. `allow_url_open` is disabled and `cURL` is not available');
|
||||
}
|
||||
|
||||
// disable time limit if possible to help with slow downloads
|
||||
if (!Utils::isFunctionDisabled('set_time_limit') && !ini_get('safe_mode')) {
|
||||
set_time_limit(0);
|
||||
}
|
||||
// check if this function is available, if so use it to stop any timeouts
|
||||
try {
|
||||
if (!Utils::isFunctionDisabled('set_time_limit') && !ini_get('safe_mode') && function_exists('set_time_limit')) {
|
||||
set_time_limit(0);
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
$options = array_replace_recursive(self::$defaults, $options);
|
||||
$method = 'get' . ucfirst(strtolower(self::$method));
|
||||
|
||||
@@ -230,7 +230,6 @@ class Grav extends Container
|
||||
|
||||
$debugger->startTimer('themes', 'Themes');
|
||||
$this['themes']->init();
|
||||
$this->fireEvent('onThemeInitialized');
|
||||
$debugger->stopTimer('themes');
|
||||
|
||||
$task = $this['task'];
|
||||
|
||||
@@ -215,4 +215,26 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sorts elements from the list and returns a copy of the list in the proper order
|
||||
*
|
||||
* @param callable|null $callback
|
||||
*
|
||||
* @param bool $desc
|
||||
*
|
||||
* @return $this|array
|
||||
* @internal param bool $asc
|
||||
*
|
||||
*/
|
||||
public function sort(callable $callback = null, $desc = false)
|
||||
{
|
||||
if (!$callback || !is_callable($callback)) { return $this; }
|
||||
|
||||
$items = $this->items;
|
||||
uasort($items, $callback);
|
||||
|
||||
return !$desc ? $items : array_reverse($items, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ class Language
|
||||
if ($this->config->get('system.languages.translations_fallback', true)) {
|
||||
$languages = $this->getFallbackLanguages();
|
||||
} else {
|
||||
$languages = (array)$this->getDefault();
|
||||
$languages = (array)$this->getLanguage();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -193,7 +193,7 @@ class LanguageCodes
|
||||
],
|
||||
"fr" => [
|
||||
"name" => "French",
|
||||
"nativeName" => "français"
|
||||
"nativeName" => "Français"
|
||||
],
|
||||
"ff" => [
|
||||
"name" => "Fula",
|
||||
|
||||
@@ -204,6 +204,48 @@ trait ParsedownGravTrait
|
||||
if (isset($excerpt['element']['attributes']['href'])) {
|
||||
$url = parse_url(htmlspecialchars_decode($excerpt['element']['attributes']['href']));
|
||||
|
||||
// if there is a query, then parse it and build action calls
|
||||
if (isset($url['query'])) {
|
||||
$actions = array_reduce(explode('&', $url['query']), function ($carry, $item) {
|
||||
$parts = explode('=', $item, 2);
|
||||
$value = isset($parts[1]) ? $parts[1] : null;
|
||||
$carry[$parts[0]] = $value;
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
// valid attributes supported
|
||||
$valid_attributes = ['rel', 'target', 'id', 'class', 'classes'];
|
||||
|
||||
// Unless told to not process, go through actions
|
||||
if (array_key_exists('noprocess', $actions)) {
|
||||
unset($actions['noprocess']);
|
||||
} else {
|
||||
// loop through actions for the image and call them
|
||||
foreach ($actions as $attrib => $value) {
|
||||
$key = $attrib;
|
||||
|
||||
if (in_array($attrib, $valid_attributes)) {
|
||||
// support both class and classes
|
||||
if ($attrib == 'classes') {
|
||||
$attrib = 'class';
|
||||
}
|
||||
$excerpt['element']['attributes'][$attrib] = $value;
|
||||
unset($actions[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$url['query']= http_build_query($actions, null, '&', PHP_QUERY_RFC3986);
|
||||
}
|
||||
|
||||
// if no query elements left, unset query
|
||||
if (empty($url['query'])) {
|
||||
unset ($url['query']);
|
||||
}
|
||||
|
||||
|
||||
// if there is no scheme, the file is local
|
||||
if (!isset($url['scheme']) && (count($url) > 0)) {
|
||||
// convert the URl is required
|
||||
|
||||
@@ -453,6 +453,55 @@ class Collection extends Iterator
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new collection with only pages of one of the specified access levels
|
||||
*
|
||||
* @return Collection The collection
|
||||
*/
|
||||
public function ofOneOfTheseAccessLevels($accessLevels)
|
||||
{
|
||||
$items = [];
|
||||
|
||||
foreach ($this->items as $path => $slug) {
|
||||
$page = $this->pages->get($path);
|
||||
|
||||
if ($page !== null && isset($page->header()->access)) {
|
||||
if (is_array($page->header()->access)) {
|
||||
//Multiple values for access
|
||||
$valid = false;
|
||||
|
||||
foreach ($page->header()->access as $index => $accessLevel) {
|
||||
if (is_array($accessLevel)) {
|
||||
foreach($accessLevel as $innerIndex => $innerAccessLevel) {
|
||||
if (in_array($innerAccessLevel, $accessLevels)) {
|
||||
$valid = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (in_array($index, $accessLevels)) {
|
||||
$valid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($valid) {
|
||||
$items[$path] = $slug;
|
||||
}
|
||||
} else {
|
||||
//Single value for access
|
||||
if (in_array($page->header()->access, $accessLevels)) {
|
||||
$items[$path] = $slug;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$this->items = $items;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ class ImageFile extends Image
|
||||
$cacheFile .= $this->prettyName;
|
||||
}
|
||||
|
||||
|
||||
$cacheFile .= '.'.$type;
|
||||
|
||||
// If the files does not exists, save it
|
||||
@@ -79,7 +80,8 @@ class ImageFile extends Image
|
||||
|
||||
// Asking the cache for the cacheFile
|
||||
try {
|
||||
$file = $this->cache->getOrCreateFile($cacheFile, $conditions, $generate, $actual);
|
||||
$perms = octdec(self::getGrav()['config']->get('system.images.cache_perms', '0755'));
|
||||
$file = $this->cache->setDirectoryMode($perms)->getOrCreateFile($cacheFile, $conditions, $generate, $actual);
|
||||
} catch (GenerationError $e) {
|
||||
$file = $e->getNewFile();
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ class ImageMedium extends Medium
|
||||
*/
|
||||
public function url($reset = true)
|
||||
{
|
||||
$output = preg_replace('|^' . GRAV_ROOT . '|', '', $this->saveImage());
|
||||
$output = preg_replace('|^' . preg_quote(GRAV_ROOT) . '|', '', $this->saveImage());
|
||||
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
|
||||
@@ -137,7 +137,7 @@ class Medium extends Data implements RenderableInterface
|
||||
*/
|
||||
public function url($reset = true)
|
||||
{
|
||||
$output = preg_replace('|^' . GRAV_ROOT . '|', '', $this->get('filepath'));
|
||||
$output = preg_replace('|^' . preg_quote(GRAV_ROOT) . '|', '', $this->get('filepath'));
|
||||
|
||||
if ($reset) {
|
||||
$this->reset();
|
||||
@@ -214,8 +214,9 @@ class Medium extends Data implements RenderableInterface
|
||||
else
|
||||
$style .= $key . ': ' . $value . ';';
|
||||
}
|
||||
if ($style)
|
||||
if ($style) {
|
||||
$attributes['style'] = $style;
|
||||
}
|
||||
|
||||
if (empty($attributes['title'])) {
|
||||
if (!empty($title)) {
|
||||
@@ -392,6 +393,38 @@ class Medium extends Data implements RenderableInterface
|
||||
return $this->link($reset, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a class to the element from Markdown or Twig
|
||||
* Example:  or 
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function classes()
|
||||
{
|
||||
$classes = func_get_args();
|
||||
if (!empty($classes)) {
|
||||
$this->attributes['class'] = implode(',', (array)$classes);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an id to the element from Markdown or Twig
|
||||
* Example: 
|
||||
*
|
||||
* @param $id
|
||||
* @return $this
|
||||
*/
|
||||
public function id($id)
|
||||
{
|
||||
if (is_string($id)) {
|
||||
$this->attributes['id'] = trim($id);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to add an inline style attribute from Markdown or Twig
|
||||
* Example: 
|
||||
|
||||
@@ -5,6 +5,7 @@ use Exception;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\GravTrait;
|
||||
use Grav\Common\Language\Language;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Common\Cache;
|
||||
use Grav\Common\Twig;
|
||||
@@ -381,7 +382,7 @@ class Page
|
||||
*/
|
||||
public function modifyHeader($key, $value)
|
||||
{
|
||||
$this->header->$key = $value;
|
||||
$this->header->{$key} = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -392,8 +393,7 @@ class Page
|
||||
*/
|
||||
public function summary($size = null)
|
||||
{
|
||||
/** @var Config $config */
|
||||
$config = self::getGrav()['config']->get('site.summary');
|
||||
$config = (array) self::getGrav()['config']->get('site.summary');
|
||||
if (isset($this->header->summary)) {
|
||||
$config = array_merge($config, $this->header->summary);
|
||||
}
|
||||
@@ -728,27 +728,30 @@ class Page
|
||||
* You need to call $this->save() in order to perform the move.
|
||||
*
|
||||
* @param Page $parent New parent page.
|
||||
* @return Page
|
||||
* @return $this
|
||||
*/
|
||||
public function move(Page $parent)
|
||||
{
|
||||
$clone = clone $this;
|
||||
$clone->_action = 'move';
|
||||
$clone->_original = $this;
|
||||
$clone->parent($parent);
|
||||
$clone->id(time().md5($clone->filePath()));
|
||||
if (!$this->_original) {
|
||||
$clone = clone $this;
|
||||
$this->_original = $clone;
|
||||
}
|
||||
|
||||
$this->_action = 'move';
|
||||
$this->parent($parent);
|
||||
$this->id(time().md5($this->filePath()));
|
||||
|
||||
if ($parent->path()) {
|
||||
$clone->path($parent->path() . '/' . $clone->folder());
|
||||
$this->path($parent->path() . '/' . $this->folder());
|
||||
}
|
||||
|
||||
if ($parent->route()) {
|
||||
$clone->route($parent->route() . '/'. $clone->slug());
|
||||
$this->route($parent->route() . '/'. $this->slug());
|
||||
} else {
|
||||
$clone->route(self::getGrav()['pages']->root()->route() . '/'. $clone->slug());
|
||||
$this->route(self::getGrav()['pages']->root()->route() . '/'. $this->slug());
|
||||
}
|
||||
|
||||
return $clone;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -758,14 +761,14 @@ class Page
|
||||
* You need to call $this->save() in order to perform the move.
|
||||
*
|
||||
* @param Page $parent New parent page.
|
||||
* @return Page
|
||||
* @return $this
|
||||
*/
|
||||
public function copy($parent)
|
||||
{
|
||||
$clone = $this->move($parent);
|
||||
$clone->_action = 'copy';
|
||||
$this->move($parent);
|
||||
$this->_action = 'copy';
|
||||
|
||||
return $clone;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -826,7 +829,7 @@ class Page
|
||||
$blueprints = $this->blueprints();
|
||||
$values = $blueprints->filter($this->toArray());
|
||||
if ($values && isset($values['header'])) {
|
||||
$this->header($values['header']);
|
||||
$this->header($values['header']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1805,11 +1808,13 @@ class Page
|
||||
|
||||
if (isset($routes[$uri_path])) {
|
||||
$child_page = $pages->dispatch($uri->route())->parent();
|
||||
if ($child_page) while (!$child_page->root()) {
|
||||
if ($this->path() == $child_page->path()) {
|
||||
return true;
|
||||
if ($child_page) {
|
||||
while (!$child_page->root()) {
|
||||
if ($this->path() == $child_page->path()) {
|
||||
return true;
|
||||
}
|
||||
$child_page = $child_page->parent();
|
||||
}
|
||||
$child_page = $child_page->parent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1843,7 +1848,7 @@ class Page
|
||||
/**
|
||||
* Helper method to return a page.
|
||||
*
|
||||
* @param string $url the url of the page
|
||||
* @param string $url the url of the page
|
||||
* @param bool $all
|
||||
*
|
||||
* @return \Grav\Common\Page\Page page you were looking for if it exists
|
||||
@@ -1951,7 +1956,7 @@ class Page
|
||||
* @return mixed
|
||||
* @internal
|
||||
*/
|
||||
protected function evaluate($value)
|
||||
public function evaluate($value)
|
||||
{
|
||||
// Parse command.
|
||||
if (is_string($value)) {
|
||||
@@ -2002,16 +2007,16 @@ class Page
|
||||
case 'children':
|
||||
$results = $this->children()->nonModular();
|
||||
break;
|
||||
|
||||
case 'all':
|
||||
$results = $this->children();
|
||||
break;
|
||||
case 'parent':
|
||||
$collection = new Collection();
|
||||
$results = $collection->addPage($this->parent());
|
||||
break;
|
||||
|
||||
case 'siblings':
|
||||
$results = $this->parent()->children()->remove($this->path());
|
||||
break;
|
||||
|
||||
case 'descendants':
|
||||
$results = $pages->all($this)->remove($this->path())->nonModular();
|
||||
break;
|
||||
@@ -2141,7 +2146,7 @@ class Page
|
||||
*/
|
||||
protected function doRelocation($reorder)
|
||||
{
|
||||
if (empty($this->_original) ) {
|
||||
if (!$this->_original) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2182,7 +2187,7 @@ class Page
|
||||
// Handle all the other pages.
|
||||
$page = $pages->get($path);
|
||||
|
||||
if ($page && $page->exists() && $page->order() != $order+1) {
|
||||
if ($page && $page->exists() && !$page->_action && $page->order() != $order+1) {
|
||||
$page = $page->move($parent);
|
||||
$page->order($order+1);
|
||||
$page->save(false);
|
||||
@@ -2190,11 +2195,12 @@ class Page
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->_action == 'move' && $this->_original->exists()) {
|
||||
Folder::move($this->_original->path(), $this->path());
|
||||
}
|
||||
if ($this->_action == 'copy' && $this->_original->exists()) {
|
||||
Folder::copy($this->_original->path(), $this->path());
|
||||
if (is_dir($this->_original->path())) {
|
||||
if ($this->_action == 'move') {
|
||||
Folder::move($this->_original->path(), $this->path());
|
||||
} elseif ($this->_action == 'copy') {
|
||||
Folder::copy($this->_original->path(), $this->path());
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->name() != $this->_original->name()) {
|
||||
@@ -2204,7 +2210,6 @@ class Page
|
||||
}
|
||||
}
|
||||
|
||||
$this->_action = null;
|
||||
$this->_original = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ class Pages
|
||||
/**
|
||||
* Get a page instance.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $path The filesystem full path of the page
|
||||
* @return Page
|
||||
* @throws \Exception
|
||||
*/
|
||||
@@ -264,7 +264,7 @@ class Pages
|
||||
/**
|
||||
* Dispatch URI to a page.
|
||||
*
|
||||
* @param $url
|
||||
* @param string $url The relative URL of the page
|
||||
* @param bool $all
|
||||
* @return Page|null
|
||||
*/
|
||||
@@ -486,6 +486,36 @@ class Pages
|
||||
return static::types();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access levels of the site pages
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function accessLevels()
|
||||
{
|
||||
$accessLevels = [];
|
||||
foreach($this->all() as $page) {
|
||||
if (isset($page->header()->access)) {
|
||||
if (is_array($page->header()->access)) {
|
||||
foreach($page->header()->access as $index => $accessLevel) {
|
||||
if (is_array($accessLevel)) {
|
||||
foreach($accessLevel as $innerIndex => $innerAccessLevel) {
|
||||
array_push($accessLevels, $innerIndex);
|
||||
}
|
||||
} else {
|
||||
array_push($accessLevels, $index);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
array_push($accessLevels, $page->header()->access);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($accessLevels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available parents.
|
||||
*
|
||||
@@ -498,7 +528,22 @@ class Pages
|
||||
/** @var Pages $pages */
|
||||
$pages = $grav['pages'];
|
||||
|
||||
return $pages->getList();
|
||||
$parents = $pages->getList();
|
||||
|
||||
/** @var Admin $admin */
|
||||
$admin = $grav['admin'];
|
||||
|
||||
// Remove current route from parents
|
||||
if (isset($admin)) {
|
||||
$page = $admin->getPage($admin->route);
|
||||
$page_route = $page->route();
|
||||
if (isset($parents[$page_route])) {
|
||||
unset($parents[$page_route]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $parents;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -104,8 +104,12 @@ class Plugins extends Iterator
|
||||
continue;
|
||||
}
|
||||
|
||||
$type = $directory->getBasename();
|
||||
$list[$type] = self::get($type);
|
||||
$plugin = $directory->getBasename();
|
||||
$result = self::get($plugin);
|
||||
|
||||
if ($result) {
|
||||
$list[$plugin] = $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
ksort($list);
|
||||
@@ -120,9 +124,9 @@ class Plugins extends Iterator
|
||||
$blueprint->name = $name;
|
||||
|
||||
// Load default configuration.
|
||||
$file = CompiledYamlFile::instance("plugins://{$name}/{$name}.yaml");
|
||||
$file = CompiledYamlFile::instance("plugins://{$name}/{$name}" . YAML_EXT);
|
||||
|
||||
// ensure the plugin exists physically
|
||||
// ensure this is a valid plugin
|
||||
if (!$file->exists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
<?php
|
||||
namespace Grav\Common\Service;
|
||||
|
||||
use Grav\Common\Config\CompiledBlueprints;
|
||||
use Grav\Common\Config\CompiledConfig;
|
||||
use Grav\Common\Config\CompiledLanguages;
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Config\ConfigFileFinder;
|
||||
use Grav\Common\Config\Setup;
|
||||
use Pimple\Container;
|
||||
use Pimple\ServiceProviderInterface;
|
||||
use RocketTheme\Toolbox\Blueprints\Blueprints;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
/**
|
||||
* The Config class contains configuration information.
|
||||
@@ -14,51 +19,99 @@ use RocketTheme\Toolbox\Blueprints\Blueprints;
|
||||
*/
|
||||
class ConfigServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
private $environment;
|
||||
private $setup;
|
||||
|
||||
public function register(Container $container)
|
||||
{
|
||||
$self = $this;
|
||||
|
||||
// Pre-load setup.php as it contains our initial configuration.
|
||||
$file = GRAV_ROOT . '/setup.php';
|
||||
$this->setup = is_file($file) ? (array) include $file : [];
|
||||
$this->environment = isset($this->setup['environment']) ? $this->setup['environment'] : null;
|
||||
|
||||
$container['blueprints'] = function ($c) use ($self) {
|
||||
return $self->loadMasterBlueprints($c);
|
||||
$container['setup'] = function ($c) {
|
||||
return static::setup($c)->init();
|
||||
};
|
||||
|
||||
$container['config'] = function ($c) use ($self) {
|
||||
return $self->loadMasterConfig($c);
|
||||
$container['blueprints'] = function ($c) {
|
||||
return static::blueprints($c);
|
||||
};
|
||||
|
||||
$container['config'] = function ($c) {
|
||||
return static::load($c);
|
||||
};
|
||||
|
||||
$container['languages'] = function ($c) {
|
||||
return static::languages($c);
|
||||
};
|
||||
}
|
||||
|
||||
public function loadMasterConfig(Container $container)
|
||||
public static function setup(Container $container)
|
||||
{
|
||||
$environment = $this->getEnvironment($container);
|
||||
|
||||
$config = new Config($this->setup, $container, $environment);
|
||||
|
||||
return $config;
|
||||
return new Setup($container);
|
||||
}
|
||||
|
||||
public function loadMasterBlueprints(Container $container)
|
||||
public static function blueprints(Container $container)
|
||||
{
|
||||
$environment = $this->getEnvironment($container);
|
||||
$file = CACHE_DIR . 'compiled/blueprints/master-'.$environment.'.php';
|
||||
$data = is_file($file) ? (array) include $file : [];
|
||||
/** Setup $setup */
|
||||
$setup = $container['setup'];
|
||||
|
||||
return new Blueprints($data, $container);
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $container['locator'];
|
||||
|
||||
$cache = $locator->findResource('cache://compiled/blueprints', true, true);
|
||||
|
||||
$files = [];
|
||||
$paths = $locator->findResources('blueprints://config');
|
||||
$files += (new ConfigFileFinder)->locateFiles($paths);
|
||||
$paths = $locator->findResources('plugins://');
|
||||
$files += (new ConfigFileFinder)->setBase('plugins')->locateInFolders($paths, 'blueprints');
|
||||
|
||||
$blueprints = new CompiledBlueprints($cache, $files, GRAV_ROOT);
|
||||
|
||||
return $blueprints->name("master-{$setup->environment}")->load();
|
||||
}
|
||||
|
||||
public function getEnvironment(Container $container)
|
||||
public static function load(Container $container)
|
||||
{
|
||||
if (!isset($this->environment)) {
|
||||
$this->environment = $container['uri']->environment();
|
||||
/** Setup $setup */
|
||||
$setup = $container['setup'];
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $container['locator'];
|
||||
|
||||
$cache = $locator->findResource('cache://compiled/config', true, true);
|
||||
|
||||
$files = [];
|
||||
$paths = $locator->findResources('config://');
|
||||
$files += (new ConfigFileFinder)->locateFiles($paths);
|
||||
$paths = $locator->findResources('plugins://');
|
||||
$files += (new ConfigFileFinder)->setBase('plugins')->locateInFolders($paths);
|
||||
|
||||
$config = new CompiledConfig($cache, $files, GRAV_ROOT);
|
||||
$config->setBlueprints(function() use ($container) {
|
||||
return $container['blueprints'];
|
||||
});
|
||||
|
||||
return $config->name("master-{$setup->environment}")->load();
|
||||
}
|
||||
|
||||
public static function languages(Container $container)
|
||||
{
|
||||
/** Setup $setup */
|
||||
$setup = $container['setup'];
|
||||
|
||||
/** @var Config $config */
|
||||
$config = $container['config'];
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $container['locator'];
|
||||
|
||||
$cache = $locator->findResource('cache://compiled/languages', true, true);
|
||||
$files = [];
|
||||
|
||||
// Process languages only if enabled in configuration.
|
||||
if ($config->get('system.languages.translations', true)) {
|
||||
$paths = $locator->findResources('languages://');
|
||||
$files += (new ConfigFileFinder)->locateFiles($paths);
|
||||
$paths = $locator->findResources('plugins://');
|
||||
$files += (new ConfigFileFinder)->setBase('plugins')->locateInFolders($paths, 'languages');
|
||||
}
|
||||
|
||||
return $this->environment;
|
||||
$languages = new CompiledLanguages($cache, $files, GRAV_ROOT);
|
||||
|
||||
return $languages->name("master-{$setup->environment}")->load();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace Grav\Common\Service;
|
||||
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Config\Setup;
|
||||
use Pimple\Container;
|
||||
use RocketTheme\Toolbox\DI\ServiceProviderInterface;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
@@ -14,18 +14,18 @@ class StreamsServiceProvider implements ServiceProviderInterface
|
||||
public function register(Container $container)
|
||||
{
|
||||
$container['locator'] = function($c) {
|
||||
$locator = new UniformResourceLocator(ROOT_DIR);
|
||||
$locator = new UniformResourceLocator(GRAV_ROOT);
|
||||
|
||||
/** @var Config $config */
|
||||
$config = $c['config'];
|
||||
$config->initializeLocator($locator);
|
||||
/** @var Setup $setup */
|
||||
$setup = $c['setup'];
|
||||
$setup->initializeLocator($locator);
|
||||
|
||||
return $locator;
|
||||
};
|
||||
|
||||
$container['streams'] = function($c) {
|
||||
/** @var Config $config */
|
||||
$config = $c['config'];
|
||||
/** @var Setup $setup */
|
||||
$setup = $c['setup'];
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $c['locator'];
|
||||
@@ -34,7 +34,7 @@ class StreamsServiceProvider implements ServiceProviderInterface
|
||||
Stream::setLocator($locator);
|
||||
ReadOnlyStream::setLocator($locator);
|
||||
|
||||
return new StreamBuilder($config->getStreams($c));
|
||||
return new StreamBuilder($setup->getStreams($c));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ class Themes extends Iterator
|
||||
|
||||
public function __construct(Grav $grav)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->grav = $grav;
|
||||
$this->config = $grav['config'];
|
||||
|
||||
@@ -34,13 +36,18 @@ class Themes extends Iterator
|
||||
|
||||
public function init()
|
||||
{
|
||||
/** @var EventDispatcher $events */
|
||||
$events = $this->grav['events'];
|
||||
|
||||
/** @var Themes $themes */
|
||||
$themes = $this->grav['themes'];
|
||||
$themes->configure();
|
||||
|
||||
$this->initTheme();
|
||||
}
|
||||
|
||||
public function initTheme()
|
||||
{
|
||||
/** @var Themes $themes */
|
||||
$themes = $this->grav['themes'];
|
||||
|
||||
try {
|
||||
$instance = $themes->load();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
@@ -48,10 +55,15 @@ class Themes extends Iterator
|
||||
}
|
||||
|
||||
if ($instance instanceof EventSubscriberInterface) {
|
||||
/** @var EventDispatcher $events */
|
||||
$events = $this->grav['events'];
|
||||
|
||||
$events->addSubscriber($instance);
|
||||
}
|
||||
|
||||
$this->grav['theme'] = $instance;
|
||||
|
||||
$this->grav->fireEvent('onThemeInitialized');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,8 +86,12 @@ class Themes extends Iterator
|
||||
continue;
|
||||
}
|
||||
|
||||
$type = $directory->getBasename();
|
||||
$list[$type] = self::get($type);
|
||||
$theme = $directory->getBasename();
|
||||
$result = self::get($theme);
|
||||
|
||||
if ($result) {
|
||||
$list[$theme] = $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
ksort($list);
|
||||
@@ -100,14 +116,20 @@ class Themes extends Iterator
|
||||
$blueprint = $blueprints->get("{$name}/blueprints");
|
||||
$blueprint->name = $name;
|
||||
|
||||
// Load default configuration.
|
||||
$file = CompiledYamlFile::instance("themes://{$name}/{$name}" . YAML_EXT);
|
||||
|
||||
// ensure this is a valid theme
|
||||
if (!$file->exists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find thumbnail.
|
||||
$thumb = "themes://{$name}/thumbnail.jpg";
|
||||
if ($path = $this->grav['locator']->findResource($thumb, false)) {
|
||||
$blueprint->set('thumbnail', $this->grav['base_url'] . '/' . $path);
|
||||
}
|
||||
|
||||
// Load default configuration.
|
||||
$file = CompiledYamlFile::instance("themes://{$name}/{$name}" . YAML_EXT);
|
||||
$obj = new Data($file->content(), $blueprint);
|
||||
|
||||
// Override with user configuration.
|
||||
|
||||
@@ -355,6 +355,12 @@ class TwigExtension extends \Twig_Extension
|
||||
$periods[$j] .= '_PLURAL';
|
||||
}
|
||||
|
||||
if ($this->grav['language']->getTranslation($this->grav['language']->getLanguage(), $periods[$j] . '_MORE_THAN_TWO')) {
|
||||
if ($difference > 2) {
|
||||
$periods[$j] .= '_MORE_THAN_TWO';
|
||||
}
|
||||
}
|
||||
|
||||
$periods[$j] = $this->grav['language']->translate($periods[$j], null, true);
|
||||
|
||||
return "$difference $periods[$j] {$tense}";
|
||||
|
||||
127
system/src/Grav/Common/User/Group.php
Normal file
127
system/src/Grav/Common/User/Group.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
namespace Grav\Common\User;
|
||||
|
||||
use Grav\Common\Data\Blueprints;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\GravTrait;
|
||||
use Grav\Common\Utils;
|
||||
|
||||
/**
|
||||
* Group object
|
||||
*
|
||||
* @property mixed authenticated
|
||||
* @property mixed password
|
||||
* @property bool|string hashed_password
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Group extends Data
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
/**
|
||||
* Get the groups list
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function groups()
|
||||
{
|
||||
$groups = self::getGrav()['config']->get('groups');
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a group exists
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public static function group_exists($groupname)
|
||||
{
|
||||
return isset(self::groups()[$groupname]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a group by name
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public static function load($groupname)
|
||||
{
|
||||
if (self::group_exists($groupname)) {
|
||||
$content = self::groups()[$groupname];
|
||||
} else {
|
||||
$content = [];
|
||||
}
|
||||
|
||||
$blueprints = new Blueprints('blueprints://');
|
||||
$blueprint = $blueprints->get('user/group');
|
||||
if (!isset($content['groupname'])) {
|
||||
$content['groupname'] = $groupname;
|
||||
}
|
||||
$group = new Group($content, $blueprint);
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a group
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$blueprints = new Blueprints('blueprints://');
|
||||
$blueprint = $blueprints->get('user/group');
|
||||
|
||||
$fields = $blueprint->fields();
|
||||
|
||||
self::getGrav()['config']->set("groups.$this->groupname", []);
|
||||
|
||||
foreach($fields as $field) {
|
||||
if ($field['type'] == 'text') {
|
||||
$value = $field['name'];
|
||||
if (isset($this->items[$value])) {
|
||||
self::getGrav()['config']->set("groups.$this->groupname.$value", $this->items[$value]);
|
||||
}
|
||||
}
|
||||
if ($field['type'] == 'array') {
|
||||
$value = $field['name'];
|
||||
$arrayValues = Utils::resolve($this->items, $field['name']);
|
||||
|
||||
if ($arrayValues) foreach($arrayValues as $arrayIndex => $arrayValue) {
|
||||
self::getGrav()['config']->set("groups.$this->groupname.$value.$arrayIndex", $arrayValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$type = 'groups';
|
||||
$blueprints = $this->blueprints("config/{$type}");
|
||||
$obj = new Data(self::getGrav()['config']->get($type), $blueprints);
|
||||
$file = CompiledYamlFile::instance(self::getGrav()['locator']->findResource("config://{$type}.yaml"));
|
||||
$obj->file($file);
|
||||
$obj->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a group
|
||||
*
|
||||
* @param string $username
|
||||
* @return bool True if the action was performed
|
||||
*/
|
||||
public static function remove($groupname)
|
||||
{
|
||||
$blueprints = new Blueprints('blueprints://');
|
||||
$blueprint = $blueprints->get('user/group');
|
||||
|
||||
$groups = self::getGrav()['config']->get("groups");
|
||||
unset($groups[$groupname]);
|
||||
self::getGrav()['config']->set("groups", $groups);
|
||||
|
||||
$type = 'groups';
|
||||
$obj = new Data(self::getGrav()['config']->get($type), $blueprint);
|
||||
$file = CompiledYamlFile::instance(self::getGrav()['locator']->findResource("config://{$type}.yaml"));
|
||||
$obj->file($file);
|
||||
$obj->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,9 @@ class User extends Data
|
||||
{
|
||||
$locator = self::getGrav()['locator'];
|
||||
|
||||
// force lowercase of username
|
||||
$username = strtolower($username);
|
||||
|
||||
$blueprints = new Blueprints('blueprints://');
|
||||
$blueprint = $blueprints->get('user/account');
|
||||
$file_path = $locator->findResource('account://' . $username . YAML_EXT);
|
||||
@@ -53,7 +56,7 @@ class User extends Data
|
||||
* Remove user account.
|
||||
*
|
||||
* @param string $username
|
||||
* @return bool True is the action was performed
|
||||
* @return bool True if the action was performed
|
||||
*/
|
||||
public static function remove($username)
|
||||
{
|
||||
@@ -83,7 +86,10 @@ class User extends Data
|
||||
// Plain-text passwords do not match, we know we should fail but execute
|
||||
// verify to protect us from timing attacks and return false regardless of
|
||||
// the result
|
||||
Authentication::verify($password, self::getGrav()['config']->get('system.security.default_hash'));
|
||||
Authentication::verify(
|
||||
$password,
|
||||
self::getGrav()['config']->get('system.security.default_hash', '$2y$10$kwsyMVwM8/7j0K/6LHT.g.Fs49xOCTp2b8hh/S5.dPJuJcJB6T.UK')
|
||||
);
|
||||
return false;
|
||||
} else {
|
||||
// Plain-text does match, we can update the hash and proceed
|
||||
@@ -146,7 +152,28 @@ class User extends Data
|
||||
return false;
|
||||
}
|
||||
|
||||
return Utils::isPositive($this->get("access.{$action}"));
|
||||
$return = false;
|
||||
|
||||
//Check group access level
|
||||
$groups = $this->get('groups');
|
||||
if ($groups) foreach($groups as $group) {
|
||||
$permission = self::getGrav()['config']->get("groups.{$group}.access.{$action}");
|
||||
if (Utils::isPositive($permission)) {
|
||||
$return = true;
|
||||
}
|
||||
}
|
||||
|
||||
//Check user access level
|
||||
if (!$this->get('access')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Utils::resolve($this->get('access'), $action) !== null) {
|
||||
$permission = $this->get("access.{$action}");
|
||||
$return = Utils::isPositive($permission);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,8 @@ abstract class Utils
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
protected static $nonces = [];
|
||||
|
||||
/**
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
@@ -217,9 +219,11 @@ abstract class Utils
|
||||
$filesize = filesize($file);
|
||||
|
||||
// check if this function is available, if so use it to stop any timeouts
|
||||
if (function_exists('set_time_limit')) {
|
||||
set_time_limit(0);
|
||||
}
|
||||
try {
|
||||
if (!Utils::isFunctionDisabled('set_time_limit') && !ini_get('safe_mode') && function_exists('set_time_limit')) {
|
||||
set_time_limit(0);
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
ignore_user_abort(false);
|
||||
|
||||
@@ -409,6 +413,25 @@ abstract class Utils
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value of an array using dot notation
|
||||
*/
|
||||
public static function resolve(array $array, $path, $default = null)
|
||||
{
|
||||
$current = $array;
|
||||
$p = strtok($path, '.');
|
||||
|
||||
while ($p !== false) {
|
||||
if (!isset($current[$p])) {
|
||||
return $default;
|
||||
}
|
||||
$current = $current[$p];
|
||||
$p = strtok('.');
|
||||
}
|
||||
|
||||
return $current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a value is positive
|
||||
*
|
||||
@@ -421,7 +444,6 @@ abstract class Utils
|
||||
return in_array($value, [true, 1, '1', 'yes', 'on', 'true'], true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a nonce string to be hashed. Called by self::getNonce()
|
||||
*
|
||||
@@ -435,11 +457,10 @@ abstract class Utils
|
||||
if (isset(self::getGrav()['user'])) {
|
||||
$user = self::getGrav()['user'];
|
||||
$username = $user->username;
|
||||
if (isset($_SERVER['REMOTE_ADDR'])) {
|
||||
$username .= $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
} else {
|
||||
$username = false;
|
||||
}
|
||||
|
||||
if (!$username) {
|
||||
$username = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
|
||||
}
|
||||
|
||||
@@ -450,7 +471,7 @@ abstract class Utils
|
||||
$i++;
|
||||
}
|
||||
|
||||
return ( $i . '|' . $action . '|' . $username . '|' . $token );
|
||||
return ( $i . '|' . $action . '|' . $username . '|' . $token . '|' . self::getGrav()['config']->get('security.salt'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -467,19 +488,6 @@ abstract class Utils
|
||||
return (int)ceil(time() / ( $secondsInHalfADay ));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hash of given string
|
||||
*
|
||||
* @param string $data string to hash
|
||||
*
|
||||
* @return string hashed value of $data, cut to 10 characters
|
||||
*/
|
||||
private static function hash($data)
|
||||
{
|
||||
$hash = password_hash($data, PASSWORD_DEFAULT);
|
||||
return $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a hashed nonce tied to the passed action. Tied to the current user and time. The nonce for a given
|
||||
* action is the same for 12 hours.
|
||||
@@ -491,9 +499,14 @@ abstract class Utils
|
||||
*/
|
||||
public static function getNonce($action, $plusOneTick = false)
|
||||
{
|
||||
$nonce = self::hash(self::generateNonceString($action, $plusOneTick));
|
||||
$nonce = str_replace('/', 'SLASH', $nonce);
|
||||
return $nonce;
|
||||
// Don't regenerate this again if not needed
|
||||
if (isset(static::$nonces[$action])) {
|
||||
return static::$nonces[$action];
|
||||
}
|
||||
$nonce = md5(self::generateNonceString($action, $plusOneTick));
|
||||
static::$nonces[$action] = $nonce;
|
||||
|
||||
return static::$nonces[$action];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -506,21 +519,18 @@ abstract class Utils
|
||||
*/
|
||||
public static function verifyNonce($nonce, $action)
|
||||
{
|
||||
$nonce = str_replace('SLASH', '/', $nonce);
|
||||
|
||||
//Nonce generated 0-12 hours ago
|
||||
if (password_verify(self::generateNonceString($action), $nonce)) {
|
||||
if ($nonce == self::getNonce($action)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Nonce generated 12-24 hours ago
|
||||
$plusOneTick = true;
|
||||
if (password_verify(self::generateNonceString($action, $plusOneTick), $nonce)) {
|
||||
if ($nonce == self::getNonce($action, $plusOneTick)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Invalid nonce
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class SandboxCommand extends ConsoleCommand
|
||||
'/.editorconfig' => '/.editorconfig',
|
||||
'/.gitignore' => '/.gitignore',
|
||||
'/CHANGELOG.md' => '/CHANGELOG.md',
|
||||
'/LICENSE' => '/LICENSE',
|
||||
'/LICENSE.txt' => '/LICENSE.txt',
|
||||
'/README.md' => '/README.md',
|
||||
'/index.php' => '/index.php',
|
||||
'/composer.json' => '/composer.json',
|
||||
|
||||
@@ -21,6 +21,16 @@ class IndexCommand extends ConsoleCommand
|
||||
*/
|
||||
protected $gpm;
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $sortKeys = ['name', 'slug', 'author', 'date'];
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -34,6 +44,43 @@ class IndexCommand extends ConsoleCommand
|
||||
InputOption::VALUE_NONE,
|
||||
'Force re-fetching the data from remote'
|
||||
)
|
||||
->addOption(
|
||||
'filter',
|
||||
'F',
|
||||
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Allows to limit the results based on one or multiple filters input. This can be either portion of a name/slug or a regex'
|
||||
)
|
||||
->addOption(
|
||||
'themes-only',
|
||||
'T',
|
||||
InputOption::VALUE_NONE,
|
||||
'Filters the results to only Themes'
|
||||
)
|
||||
->addOption(
|
||||
'plugins-only',
|
||||
'P',
|
||||
InputOption::VALUE_NONE,
|
||||
'Filters the results to only Plugins'
|
||||
)
|
||||
->addOption(
|
||||
'updates-only',
|
||||
'U',
|
||||
InputOption::VALUE_NONE,
|
||||
'Filters the results to Updatable Themes and Plugins only'
|
||||
)
|
||||
->addOption(
|
||||
'sort',
|
||||
's',
|
||||
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Allows to sort (ASC) the results based on one or multiple keys. SORT can be either "name", "slug", "author", "date"',
|
||||
['date']
|
||||
)
|
||||
->addOption(
|
||||
'desc',
|
||||
'D',
|
||||
InputOption::VALUE_NONE,
|
||||
'Reverses the order of the output.'
|
||||
)
|
||||
->setDescription("Lists the plugins and themes available for installation")
|
||||
->setHelp('The <info>index</info> command lists the plugins and themes available for installation')
|
||||
;
|
||||
@@ -44,16 +91,21 @@ class IndexCommand extends ConsoleCommand
|
||||
*/
|
||||
protected function serve()
|
||||
{
|
||||
$this->gpm = new GPM($this->input->getOption('force'));
|
||||
$this->options = $this->input->getOptions();
|
||||
|
||||
$this->gpm = new GPM($this->options['force']);
|
||||
|
||||
$this->data = $this->gpm->getRepository();
|
||||
|
||||
$this->output->writeln('');
|
||||
|
||||
foreach ($this->data as $type => $packages) {
|
||||
$data = $this->filter($this->data);
|
||||
|
||||
foreach ($data as $type => $packages) {
|
||||
$this->output->writeln("<green>" . ucfirst($type) . "</green> [ " . count($packages) . " ]");
|
||||
|
||||
$index = 0;
|
||||
$index = 0;
|
||||
$packages = $this->sort($packages);
|
||||
foreach ($packages as $slug => $package) {
|
||||
$this->output->writeln(
|
||||
// index
|
||||
@@ -108,4 +160,65 @@ class IndexCommand extends ConsoleCommand
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function filter($data)
|
||||
{
|
||||
// filtering and sorting
|
||||
if ($this->options['plugins-only']) {
|
||||
unset($data['themes']);
|
||||
}
|
||||
if ($this->options['themes-only']) {
|
||||
unset($data['plugins']);
|
||||
}
|
||||
|
||||
if ($this->options['filter'] || $this->options['updates-only'] || $this->options['desc']) {
|
||||
foreach ($data as $type => $packages) {
|
||||
foreach ($packages as $slug => $package) {
|
||||
$filter = true;
|
||||
|
||||
// Filtering by string
|
||||
if ($this->options['filter']) {
|
||||
$filter = preg_grep('/(' . (implode('|', $this->options['filter'])) . ')/i', [$slug, $package->name]);
|
||||
}
|
||||
|
||||
// Filtering updatables only
|
||||
if ($this->options['updates-only'] && $filter) {
|
||||
$method = ucfirst(preg_replace("/s$/", '', $package->package_type));
|
||||
$filter = $this->gpm->{'is' . $method . 'Updatable'}($package->slug);
|
||||
}
|
||||
|
||||
if (!$filter) {
|
||||
unset($data[$type][$slug]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $packages
|
||||
*/
|
||||
public function sort($packages)
|
||||
{
|
||||
foreach ($this->options['sort'] as $key) {
|
||||
$packages = $packages->sort(function ($a, $b) use ($key) {
|
||||
switch ($key) {
|
||||
case 'author':
|
||||
return strcmp($a->{$key}['name'], $b->{$key}['name']);
|
||||
break;
|
||||
default:
|
||||
return strcmp($a->$key, $b->$key);
|
||||
}
|
||||
}, $this->options['desc'] ? true : false);
|
||||
}
|
||||
|
||||
return $packages;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<action type="Redirect" url="error" redirectType="Permanent" />
|
||||
</rule>
|
||||
<rule name="vendor" stopProcessing="true">
|
||||
<match url="^vendor/(.*)$" ignoreCase="false" />
|
||||
<match url="^vendor/(.*)\.(txt|md|html|yaml|php|twig|sh|bat)$" ignoreCase="false" />
|
||||
<action type="Redirect" url="error" redirectType="Permanent" />
|
||||
</rule>
|
||||
</rules>
|
||||
|
||||
Reference in New Issue
Block a user