Compare commits

..

510 Commits

Author SHA1 Message Date
Andy Miller
b48449d782 Merge branch 'release/1.0.8' 2016-01-08 15:31:33 -07:00
Andy Miller
ee20bf70e0 version update 2016-01-08 15:31:23 -07:00
Andy Miller
8cb098c6e0 Removed IP stuff from nonce.. just too many scenarios where it causes problems. going to rely on session_id() for the uniqueness. 2016-01-08 15:28:03 -07:00
Andy Miller
3054a67078 Added rotate, flip and fixOrientation to available image methods 2016-01-07 18:49:09 -07:00
Andy Miller
8ca14c7c65 Merge branch 'release/1.0.7' 2016-01-07 14:21:56 -07:00
Andy Miller
6e2d9ca3cc Merge branch 'release/1.0.7' into develop 2016-01-07 14:21:56 -07:00
Andy Miller
eff72b73ab version update 2016-01-07 14:21:48 -07:00
Andy Miller
eb29d68958 Safety check for array of nonces 2016-01-07 14:10:58 -07:00
Andy Miller
e0632dee09 Merge branch 'release/1.0.7' into develop 2016-01-07 13:27:02 -07:00
Andy Miller
4549574908 Merge branch 'release/1.0.7' 2016-01-07 13:27:01 -07:00
Andy Miller
0866a62a1f version update 2016-01-07 13:26:53 -07:00
Andy Miller
1a7fd382a9 Merge branch 'feature/https_gpm_urls' into develop 2016-01-07 13:23:43 -07:00
Flavio Copes
cdc96ca574 Improve comment messages for temporary nonce methods 2016-01-07 11:59:40 +01:00
Andy Miller
d121aa3415 Use https for GPM rather than http 2016-01-06 21:54:43 -07:00
Djamil Legato
6aaeb9e1f1 Fixed typo 2016-01-06 16:24:11 -08:00
Andy Miller
fa39629104 changelog updates 2016-01-06 17:10:00 -07:00
Andy Miller
9e13593c11 Merge pull request #592 from getgrav/feature/fix-nonces-ips
Fix nonces for proxied IPs
2016-01-06 15:47:21 -07:00
Flavio Copes
0b3970d7c1 Restore old generateNonceString in generateNonceStringOldStyle 2016-01-06 23:43:18 +01:00
Flavio Copes
95c09f2ce5 Add HTTP_CLIENT_IP too 2016-01-06 23:34:28 +01:00
Flavio Copes
c78619aad3 Temp generation of older token for this release only 2016-01-06 23:19:00 +01:00
Flavio Copes
566da30513 Fix getting the user's IP address when proxied 2016-01-06 23:15:06 +01:00
Djamil Legato
f8c8ac4371 Response Class: Following redirects when open_basedir is set 2016-01-06 13:31:50 -08:00
Andy Miller
3c4dd26c20 Fix for media with + in the name 2016-01-05 15:45:58 -07:00
Andy Miller
f5fc509f14 Added cache driver setting to debug out 2016-01-05 14:59:24 -07:00
Andy Miller
2d00203a1f updated changelog 2016-01-05 12:08:44 -07:00
Flavio Copes
ac23ab21b8 Merge pull request #587 from jeromegamez/readme-changelog
Update README and CHANGELOG
2016-01-05 11:57:43 +01:00
Jérôme Gamez
0261df0d48 Update README and CHANGELOG 2016-01-05 11:17:22 +01:00
Andy Miller
2709938f9f Merge pull request #586 from jeromegamez/feature/composer-branch-alias
composer.json: Add branch alias - fine with this :) 👍
2016-01-04 17:37:08 -07:00
Jérôme Gamez
53e1c790d8 Add branch alias 2016-01-05 01:24:17 +01:00
Andy Miller
f2f9fc4ed6 Merge pull request #585 from jeromegamez/feature/composer-project
Allow grav to be installed as a composer project
2016-01-04 16:51:08 -07:00
Jérôme Gamez
3cbf9c7101 Allow grav to be installed as a composer project 2016-01-04 23:55:16 +01:00
Flavio Copes
c655d9e8fc Revert "Merge pull request #571 from getgrav/feature/gpm-avoid-reinstalling-already-installed-packages"
This reverts commit 418f0972a9, reversing
changes made to 9a777efd52.
2016-01-04 20:50:15 +01:00
Andy Miller
2ef7f7cf36 Merge branch 'feature/hide_home_in_urls' into develop 2016-01-04 11:14:57 -07:00
Andy Miller
418f0972a9 Merge pull request #571 from getgrav/feature/gpm-avoid-reinstalling-already-installed-packages
Command line GPM: Avoid prompting to reinstall already installed packages
2016-01-04 10:36:10 -07:00
Andy Miller
9a777efd52 Merge pull request #569 from getgrav/feature/improve-gpm-unreachable-error-message
Improve error when trying to install a plugin/theme from the command line and GPM is unreachable
2016-01-04 10:30:22 -07:00
Andy Miller
aa8a329c7b Merge pull request #557 from getgrav/feature/use-rawurldecode
Allows '+' in the URLs, such as http://localhost/grav/blog/tag:c++
2016-01-04 10:19:18 -07:00
Andy Miller
e4930a144f Merge pull request #554 from getgrav/feature/session-improvements
Add secure and httponly parameters to sessions
2016-01-04 09:54:49 -07:00
Matias Griese
194014007f Merge pull request #583 from getgrav/feature/fix-checksum
Call finalizeObject on Config from loadCompiledFile() when cache is already built
2016-01-04 15:22:24 +02:00
Matias Griese
dc8f2c1466 Fixed page blueprints and theme inheritance issue (#534) 2016-01-04 15:18:50 +02:00
Flavio Copes
6ee48c74f7 Call finalizeObject on Config from loadCompiledFile() when cache is already built
finalizeObject, which assigns the checksum to the Config object, was
never called after the cache was built
2016-01-03 19:10:17 +01:00
Flavio Copes
136a9e8218 Also check for GPM permissions. Fixes #579 2016-01-02 16:25:31 +01:00
Andy Miller
34045ea62b whitespace removal 2016-01-01 17:27:28 -07:00
Andy Miller
267edbee7d optimization 2015-12-31 16:25:27 -07:00
Andy Miller
da882ebcd2 set twig_first: false by default due to modular pages 2015-12-31 15:35:54 -07:00
Andy Miller
ed0ba1ed98 Merge pull request #577 from mholt/patch-1
Update Caddyfile
2015-12-31 12:42:11 -07:00
Matt Holt
ef9dd3aa28 Update Caddyfile
fastcgi was using php preset defaults, anyway
2015-12-31 12:40:56 -07:00
Andy Miller
73b9abd38b Added a global setting for twig_first processing, and set it to true (was false) 2015-12-31 12:25:22 -07:00
Andy Miller
6e399fe0ed maintain md5 keys during sorting process #566 2015-12-31 12:06:46 -07:00
Andy Miller
5f9ed17091 Added support for APCu and PHP 7.0 2015-12-31 11:47:50 -07:00
Flavio Copes
1f4b3913b6 Typo in changelog 2015-12-31 12:32:10 +01:00
Andy Miller
dc9b9509d7 Moved onPageContentProccessed into content building section so it's fired more reliably 2015-12-30 16:28:02 -07:00
Andy Miller
b4f34c8643 Added plugins config to debugger 2015-12-30 16:26:59 -07:00
Andy Miller
52544a8b25 Fix for not fully reprocessing content with cache_enable: false 2015-12-30 15:44:42 -07:00
Flavio Copes
017500a6b5 Add a Page::topParent() method to retrieve the topmost parent of a page
Adding to this branch as it's needed for the Admin change that handles
this branch change
2015-12-29 19:10:30 +01:00
Andy Miller
425ae30e62 fix for attributes on external urls 2015-12-29 09:56:13 -07:00
Andy Miller
1aa09d8987 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-12-28 15:49:25 -07:00
Andy Miller
a45196dc97 regular date: header should not impact published visibility 2015-12-28 15:49:17 -07:00
Djamil Legato
8d7ab6fdd3 Ignore security yaml 2015-12-28 12:55:34 -08:00
Andy Miller
87870bcde7 Fix for new webserver-config folder 2015-12-28 13:15:51 -07:00
Flavio Copes
9b85c1b0f7 Remove all hardcoded older PHP required version, use GRAV_PHP_MIN constant instead
Thanks @MATsxm for the hint in https://github.com/getgrav/grav/pull/570
2015-12-28 18:46:14 +01:00
Flavio Copes
104012228c Command line GPM: Avoid prompting to reinstall already installed packages 2015-12-28 18:22:16 +01:00
Flavio Copes
e3deb40f69 Improve error when trying to install a plugin/theme from the command line and GPM is unreachable
Previously it listed four times `PHP Warning:  Invalid argument
supplied for foreach()...`, now it fails with an error message
2015-12-28 08:53:23 +01:00
Flavio Copes
492b290845 Fix #565 handle case where we only have inline data for css or js 2015-12-26 08:54:33 +01:00
Andy Miller
3eb2a5664a logic to strip home from Page routes and urls (optional) 2015-12-24 17:42:02 -07:00
Djamil Legato
15fd233e56 Added new --installed-only | -I option for bin/gpm index that filters only the installed packages 2015-12-24 14:44:57 -08:00
Djamil Legato
912f697cff Give ZipBackup a larger timeout when possible (10mins) 2015-12-24 14:30:20 -08:00
Flavio Copes
d827228dc2 Add new languages to Grav 2015-12-24 19:11:24 +01:00
Flavio Copes
84073a53cb Add MONTHS_OF_THE_YEAR and DAYS_OF_THE_WEEK to the Grav language file,
Took translations from
https://github.com/getgrav/grav-theme-twentyfifteen/blob/develop/languag
es.yaml
2015-12-24 19:05:13 +01:00
Flavio Copes
f562573640 Add a contributing readme 2015-12-23 20:13:37 +01:00
Flavio Copes
66aa66954c Add empty thumb.png image as default 2015-12-23 16:30:12 +01:00
Flavio Copes
99275dfe59 Optimize images, save 38% in file size 2015-12-23 16:29:58 +01:00
Flavio Copes
efded08d6e Uses Uri::host() to calculate the host. If localhost, set it to ''
Now also works with Chrome on localhost SSL sites. The problem was,
Chrome on Localhost wants the domain to be `""` or `false` even if the
site is accessed with another domain name.
Worked fine in other browsers.
2015-12-23 09:18:27 +01:00
Andy Miller
d726f15aa3 PHP version update 2015-12-22 21:54:07 -07:00
Andy Miller
7c6cd30aea Merge branch 'release/1.0.6' into develop 2015-12-22 17:15:45 -07:00
Andy Miller
f0145aa659 Merge branch 'release/1.0.6' 2015-12-22 17:15:44 -07:00
Andy Miller
879b5ef272 version update 2015-12-22 17:15:34 -07:00
Flavio Copes
91a57e1a16 Allows '+' in the URLs, such as http://localhost/grav/blog/tag:c++ 2015-12-22 19:06:04 +01:00
Flavio Copes
3698afb8a6 Add secure and httponly parameters to sessions 2015-12-22 17:03:39 +01:00
Matias Griese
8e1b2bc6e4 FastCGI: Use Apache's mod_deflate if Grav's builtin gzip compression was turned off (#548) 2015-12-22 11:54:20 +02:00
Andy Miller
37dd107281 Revert "Fix orientation for images added via twig"
This reverts commit 484a34cd92.
2015-12-21 22:01:38 -07:00
Andy Miller
2d3b41c62d Revert "Fix for images orientation in page content"
This reverts commit 4581077dcd.
2015-12-21 22:01:32 -07:00
Andy Miller
c9b8fc0e1b Revert "Cleanup"
This reverts commit b2c7e22634.
2015-12-21 22:01:18 -07:00
Andy Miller
7eb57b674a Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-12-21 21:58:47 -07:00
Andy Miller
25b33d0204 Revert "Proposed fix for #541"
This reverts commit 6c6871f607.
2015-12-21 21:58:31 -07:00
Flavio Copes
d47faed870 Cleanup 2015-12-21 21:58:31 -07:00
Flavio Copes
9a8efdf9cd Fix for images orientation in page content 2015-12-21 21:58:31 -07:00
Flavio Copes
593fd20a15 Fix orientation for images added via twig 2015-12-21 21:58:31 -07:00
Flavio Copes
ef75582e20 Proposed fix for #541
After reading http://stackoverflow.com/a/6998242 rawurldecode (and
rawurlencode) is better over urldecode/urlencode: "rawurlencode is the
way to go most of the time. It deals with the modern scheme for URI
components, where as urlencode does things the old school way, where +
meant "space."
2015-12-21 21:58:31 -07:00
Andy Miller
7440074491 Revert "Proposed fix for #541"
This reverts commit 6c6871f607.
2015-12-21 21:46:36 -07:00
Andy Miller
9688ed0f51 Merge pull request #543 from getgrav/features/use-rawurldecode-encode
Use rawurldecode and rawurlencode instead of urldecode/urlencode
2015-12-21 21:16:59 -07:00
Andy Miller
45d415e547 Merge branch 'feature/exif-auto-fix-orientation' into develop 2015-12-21 21:13:09 -07:00
Flavio Copes
b2c7e22634 Cleanup 2015-12-21 19:18:51 +01:00
Flavio Copes
4581077dcd Fix for images orientation in page content 2015-12-21 19:10:19 +01:00
Flavio Copes
729f83b3d4 Fix regression in image parameters handling introduced in 23a9a73600
Parameters without a value (e.g. `sepia`, `grayscale`, `emboss` and
others) were not applied any more)
2015-12-21 18:02:25 +01:00
Flavio Copes
bf361db5fc File field validation, handle case multiple not specified 2015-12-21 16:26:05 +01:00
Flavio Copes
328e9b20de Also add config save to themes 2015-12-21 16:16:26 +01:00
Flavio Copes
484a34cd92 Fix orientation for images added via twig 2015-12-21 13:55:29 +01:00
Andy Miller
5ab4d916b0 tweaked whoops sidebar 2015-12-20 12:32:23 -07:00
Andy Miller
f0974e0d24 minor whoops styling 2015-12-20 12:30:15 -07:00
Andy Miller
06a5aa6d01 Manually rolled back APCu support for PHP7 until it is available in the released version of Doctrine (currently only in master branch) 2015-12-20 11:58:53 -07:00
Andy Miller
a88829bd57 Merge branch 'feature/update-whoops' into develop 2015-12-20 11:51:44 -07:00
Andy Miller
c023c74ae5 Merge branch 'feature/update-whoops' of https://github.com/getgrav/grav into feature/update-whoops 2015-12-20 11:51:14 -07:00
Andy Miller
a8ad14222d moved sample web server configs into a dedicated directory 2015-12-20 11:50:45 -07:00
Flavio Copes
6c6871f607 Proposed fix for #541
After reading http://stackoverflow.com/a/6998242 rawurldecode (and
rawurlencode) is better over urldecode/urlencode: "rawurlencode is the
way to go most of the time. It deals with the modern scheme for URI
components, where as urlencode does things the old school way, where +
meant "space."
2015-12-20 14:18:56 +01:00
Flavio Copes
5764e5e686 Merge branch 'develop' into feature/update-whoops 2015-12-20 11:52:52 +01:00
Flavio Copes
b89044a709 Fix language string 2015-12-20 11:51:48 +01:00
Flavio Copes
5fc4755d3b Merge pull request #537 from fbardel/patch-1
Update fr.yaml
2015-12-19 18:39:33 +01:00
François
2f2adaaee8 Update fr.yaml 2015-12-19 18:17:07 +01:00
Flavio Copes
e2ae24faa9 Merge branch 'develop' into feature/update-whoops 2015-12-19 15:30:08 +01:00
Flavio Copes
55bc84c118 Fix #535 case insensitive https check 2015-12-19 14:20:45 +01:00
Flavio Copes
a47d5d00b3 Merge branch 'develop' into feature/update-whoops 2015-12-19 11:53:52 +01:00
Flavio Copes
05c2b98929 Fix #523 locale in url with base_url_* variables, even if include_default_lang is set to false 2015-12-19 10:48:52 +01:00
Flavio Copes
c5d3098b25 Only call extra method on blueprints if blueprints exist
Reverts partial change made in

https://github.com/getgrav/grav/commit/ac3396e6c46f9bcd8d5cbb45370b5daad
c84aadc
2015-12-19 10:28:06 +01:00
Flavio Copes
6805f32a13 Merge pull request #533 from mikewink/patch-1
Fixed hardcoded string "Security"
2015-12-19 09:33:56 +01:00
Andy Miller
b8aa250a22 Merge branch 'develop' into feature/update-whoops 2015-12-18 23:08:31 -07:00
Andy Miller
bf05a36dfe Updated some libs 2015-12-18 23:08:14 -07:00
Andy Miller
8f9cdad916 Updated spelling in Parsedown to match imminent update 2015-12-18 20:50:27 -07:00
Djamil Legato
d2ed424a7c Fixed Travis parsing error [ci skip] 2015-12-18 16:05:35 -08:00
Andy Miller
08cbd9553f Merge branch 'release/1.0.5' 2015-12-18 16:50:33 -07:00
Andy Miller
369d2cb390 Merge branch 'release/1.0.5' into develop 2015-12-18 16:50:33 -07:00
Andy Miller
dcaa9a35c3 Missed changeling entry 2015-12-18 16:50:19 -07:00
Andy Miller
4a80691e07 version update 2015-12-18 16:49:03 -07:00
Mike Wink
215b2cdfa8 Fixed hardcoded string "Security"
Added the PLUGIN_ADMIN.SECURITY constant instead. Will add this to the admin language files too.
2015-12-19 00:12:01 +01:00
Andy Miller
425831a7ae Fix for empty file when writing cache 2015-12-18 15:09:21 -07:00
Djamil Legato
984e0455b1 'informations' is not a thing 😞 2015-12-18 13:44:59 -08:00
Djamil Legato
00ecfb30f3 Ensuring gpm selfupgrades doesn't continue if PHP min version requirement isn't met. Gracefully abort with error and details. 2015-12-18 13:38:28 -08:00
Djamil Legato
c18f20e483 Added GRAV_PHP_MIN 2015-12-18 13:37:19 -08:00
Djamil Legato
71c5ff8c51 Added new Upgrader::meetsRequirements method
Ensures the PHP version meets the Grav's mininum required one.
2015-12-18 13:35:31 -08:00
Djamil Legato
1996dd7de8 Allowing Installer to set errors as string 2015-12-18 13:33:57 -08:00
Andy Miller
e87daa2361 Added support to get plugin languages from individual language files in languages folder of plugin 2015-12-18 12:29:45 -07:00
Flavio Copes
987feb1385 Make saveConfig static so it's more easily accessible 2015-12-18 15:42:33 +01:00
Flavio Copes
8d048c689f Persists to disk the plugin parameters currently stored in the Grav Config object 2015-12-18 14:44:03 +01:00
Flavio Copes
139ef04e0a Handle non-array values in file validation 2015-12-18 10:38:10 +01:00
Flavio Copes
4c01e6c93e Merge pull request #530 from mufac/mufac-patch-1
Prevent error if no collections present
2015-12-18 10:04:11 +01:00
Andy Miller
27744ba747 Merge branch 'feature/markdown_extendability' into develop 2015-12-17 18:09:28 -07:00
Andy Miller
3d3c6f4eba missing doc blocks 2015-12-17 18:09:11 -07:00
Andy Miller
fb4abc5f5f Use Grav's version of Parsedown until PR is accepted (crossing fingers) 2015-12-17 17:52:20 -07:00
mufac
f29b141d69 Prevent error if no collections present
If there are no collections you can get a "Invalid argument supplied for foreach()" without an empty default.
2015-12-17 16:14:48 -06:00
Andy Miller
1cecd09423 requires changes in parsedown 2015-12-17 10:35:22 -07:00
Andy Miller
0142e76270 cleanup 2015-12-16 21:51:38 -07:00
Andy Miller
5f8c7f41ec Add ability to extend markdown 2015-12-16 19:50:10 -07:00
Flavio Copes
451baff26e filterFile if the file field allows multiple items returns an array, otherwise a string 2015-12-16 15:16:14 +01:00
Flavio Copes
78accfe98b Bump whoops version 2015-12-15 22:58:31 +01:00
Flavio Copes
0e8e27877e Fix https://github.com/getgrav/grav-plugin-admin/issues/335, when looping the fields param in a list field, first check it exists 2015-12-15 11:52:27 +01:00
Andy Miller
d8a993bc86 Properly convert comma to spaces for multiple attributes #518 2015-12-14 18:30:55 -07:00
Andy Miller
ec7dbbdc8b Added 7z format to standard file types #521 2015-12-14 18:13:14 -07:00
Flavio Copes
c45652de81 Make sure Grav can work with the 2.0.0-alpha1 Whoops update, and with the current 1.1 too 2015-12-14 14:21:39 +01:00
Djamil Legato
e152cfd10f Forcing travis VM to western most date and echo a Travis date to catch it on log 2015-12-12 17:47:19 -08:00
Andy Miller
747daa46f1 Merge branch 'release/1.0.4' 2015-12-12 13:03:34 -07:00
Andy Miller
17a0590ee4 Merge branch 'release/1.0.4' into develop 2015-12-12 13:03:34 -07:00
Andy Miller
653edb064b version update 2015-12-12 13:03:22 -07:00
Andy Miller
40f5d57737 Default value not in quotes. Needs to be a string for Admin compatibility - https://docs.saltstack.com/en/latest/topics/troubleshooting/yaml_idiosyncrasies.html#integers-are-parsed-as-integers 2015-12-12 08:43:41 -07:00
Flavio Copes
566c5cb38f Revert "Fix issue in images cache permissions"
This reverts commit 7e3058e3f0.
2015-12-12 10:18:32 +01:00
Flavio Copes
7e3058e3f0 Fix issue in images cache permissions
the leading '0' in the default 0755 was omitted as interpreted as an
integer, leading to errors in setting the images cache folder
permissions (not readable by Grav)
2015-12-12 10:13:21 +01:00
Djamil Legato
053d8a3fd5 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-12-11 21:17:30 -08:00
Djamil Legato
0e810c15e2 Keep going if files are not found while creating a new project 2015-12-11 21:17:19 -08:00
Andy Miller
6b9154d1f3 Fix for cleaning build on linux 2015-12-11 22:08:59 -07:00
Andy Miller
4a5a400b89 Merge branch 'release/1.0.3' 2015-12-11 21:52:41 -07:00
Andy Miller
2d7a3232cc Merge branch 'release/1.0.3' into develop 2015-12-11 21:52:41 -07:00
Andy Miller
96d7c4790f version update 2015-12-11 21:52:14 -07:00
Andy Miller
c0b9ada21c fix for Image perms on admin save 2015-12-11 21:43:32 -07:00
Djamil Legato
7b116b41ae Not meant to be checked in 2015-12-11 20:42:30 -08:00
Djamil Legato
fcdd0bc0e9 Reverted CleanCommand to pure Command 2015-12-11 20:19:57 -07:00
Djamil Legato
0619f7c656 Reverted CleanCommand to pure Command 2015-12-11 18:44:52 -08:00
Andy Miller
f7696b61d3 Merge branch 'release/1.0.2' 2015-12-11 18:51:36 -07:00
Andy Miller
48083b203a Merge branch 'release/1.0.2' into develop 2015-12-11 18:51:36 -07:00
Andy Miller
f8aa9fed91 version update 2015-12-11 18:51:26 -07:00
Andy Miller
c55521ac4a fixed timing calculation 2015-12-11 17:16:10 -07:00
Andy Miller
2bb23efa7c Merge branch 'release/1.0.1' 2015-12-11 15:38:45 -07:00
Andy Miller
cdcb76cc55 Merge branch 'release/1.0.1' into develop 2015-12-11 15:38:45 -07:00
Andy Miller
def726a012 version update 2015-12-11 15:38:08 -07:00
Andy Miller
7d1291e2b9 Fixed cleanup to take into account symfony folder changes 2015-12-11 15:17:01 -07:00
Andy Miller
a0297e9d65 Fix error that can results from enabling debugger from admin 2015-12-11 15:00:54 -07:00
Andy Miller
e4e0c06ea8 Merge branch 'release/1.0.0' 2015-12-11 14:00:21 -07:00
Andy Miller
f46ad2d032 Merge branch 'release/1.0.0' into develop 2015-12-11 14:00:21 -07:00
Andy Miller
0c807b6108 version update 2015-12-11 13:59:52 -07:00
Andy Miller
3a47d6a580 force lowercase of username 2015-12-11 10:34:59 -07:00
Andy Miller
52947b3a2c Added Image cache perms option 2015-12-10 20:51:40 -07:00
Andy Miller
eacfc798f4 wrap security section of account blueprints in an authorize check 2015-12-10 16:05:22 -07:00
Andy Miller
5c0e5f3c01 updated debugbar 2015-12-10 16:04:46 -07:00
Andy Miller
985141b842 Merge pull request #515 from lennerd/fix/medium-url
Escape graph root in page medium to work with special characters.
2015-12-10 13:27:02 -07:00
Andy Miller
1aac2ab95d Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-12-10 12:13:01 -07:00
Andy Miller
aa7d5ddf59 translate validation messages 2015-12-10 12:12:56 -07:00
Flavio Copes
e87505378d Fix a parentheses issue that changes the logic and throw an error if $value['error'] is not set 2015-12-10 19:19:32 +01:00
Matias Griese
53f097c2b3 Fix wrong ordering when moving bulk of pages 2015-12-10 11:25:14 +02:00
Matias Griese
6ea7fe9dba Fix moving page if its just placeholder 2015-12-10 11:19:56 +02:00
Matias Griese
0206f1b0c7 Fix Page::copy() and Page::move() to support multiple moves at once 2015-12-10 10:46:09 +02:00
Matias Griese
ef9f2c77dd Minor fix in Page class 2015-12-10 10:24:21 +02:00
Andy Miller
822292f541 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-12-09 10:13:53 -07:00
Andy Miller
ec08cd9374 Better fix for GPM issues 2015-12-09 10:13:44 -07:00
Flavio Copes
8fb4063cf2 Merge pull request #511 from getgrav/feature/fix-multisite-subfolder
Make $container available in setup.php
2015-12-09 17:25:31 +01:00
Lennart Hildebrandt
8a2b444c48 Escape graph root in page medium to work with special characters. 2015-12-09 12:30:08 +01:00
Andy Miller
9c6f243902 Fix for GPM problems "Call to a member function set() on null" 2015-12-08 21:20:41 -07:00
Andy Miller
d5bd99b363 Fix for individual asset pipeline value not functioning + optimizations #513 2015-12-08 11:42:39 -07:00
Matias Griese
5554c07cbf Merge pull request #508 from getgrav/feature/gantry
Add support to manually initialize theme
2015-12-08 10:12:00 +02:00
Andy Miller
acd95aac6f Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-12-07 16:46:37 -07:00
Andy Miller
8ad5f2624d Added iconv polyfill library 2015-12-07 16:46:28 -07:00
Andy Miller
8adc0e1c17 Merge pull request #510 from getgrav/feature/fix-translation
Fix issue when `translations_fallback` is turned off, the translations are always relative to the default language even if the active language is != default
2015-12-07 15:29:56 -07:00
Flavio Copes
fab66cf3a5 Make $container available in setup.php 2015-12-07 19:20:10 +01:00
Flavio Copes
5df48e7a68 Fix issue when translations_fallback is turned off, the translations are always relative to the default language even if the active language is != default 2015-12-07 16:25:46 +01:00
Djamil Legato
079a8c5728 Fixed LICENSE link 2015-12-06 13:24:27 -08:00
Flavio Copes
d9196426a1 Hide the session setting in admin as turning it off crashes the admin. 2015-12-06 18:20:16 +01:00
Flavio Copes
2f686f5b74 Improve a couple page method docs 2015-12-06 18:19:21 +01:00
Djamil Legato
c4b5df20a9 🎈 Added many more gpm index options (--filter, --sort, --updates-only, --plugins-only, --themes-only, --desc) 2015-12-04 17:54:14 -08:00
Djamil Legato
06608a6d3c Implemented sort method for Iterator ($iterator->sort($callback)) 2015-12-04 17:39:49 -08:00
Andy Miller
fd63911faf Useful cache info output 2015-12-04 15:50:04 -07:00
Flavio Copes
66a1e55867 Update pages blueprints to add the page preview in the markdown editor with the current admin changes 2015-12-04 23:12:36 +01:00
Andy Miller
af2eb2e75d Reverted PHP7 apcu as it seems to kill Doctrine Cache 2015-12-04 15:02:26 -07:00
Andy Miller
9b4f32cafd Merge branch 'develop' into feature/gantry 2015-12-03 22:15:17 -07:00
Andy Miller
9179fbd1a2 minor performance optimization 2015-12-03 22:12:01 -07:00
Andy Miller
24ea7f1f55 Support APCu extension loaded for PHP7.0 2015-12-03 19:05:53 -07:00
Andy Miller
9b95053110 Support APCu extension loaded for PHP7.0 2015-12-03 19:05:36 -07:00
Andy Miller
71ffb9c72f Merge branch 'develop' into feature/gantry 2015-12-03 18:06:30 -07:00
Andy Miller
f29f698f61 setter method to allow explicit setting of asset timestamp 2015-12-03 16:56:30 -07:00
Andy Miller
f1f8579a0b New setters to set state of CSS / JS pipelining 2015-12-03 14:48:34 -07:00
Andy Miller
4ca8fab750 removed unused Plugin and Theme initialization 2015-12-03 14:48:15 -07:00
Andy Miller
b80ed731b0 Made Page.evaluate() public so it can be used by twig, plugins etc. 2015-12-03 13:44:25 -07:00
Andy Miller
23a9a73600 Added logic to support link attributes via query string 2015-12-03 12:16:16 -07:00
Djamil Legato
dc8c0b6522 Fixed changelog differ to take into account betas/rc versions (fixes #496) 2015-12-02 23:44:18 -08:00
Andy Miller
e695b1942c .gitignore for accounts - https://github.com/getgrav/grav-plugin-login/issues/16 2015-12-02 15:38:05 -07:00
Andy Miller
3f543e7e84 Merge branch 'feature/gantry' of https://github.com/getgrav/grav into feature/gantry 2015-12-02 15:36:22 -07:00
Andy Miller
7f6f9e82e3 .gitignore for accounts - https://github.com/getgrav/grav-plugin-login/issues/16 2015-12-02 15:36:16 -07:00
Djamil Legato
51529eb0ce Merge branch 'develop' into feature/gantry 2015-12-02 14:10:17 -08:00
Andy Miller
05b24a4b75 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-12-02 12:39:01 -07:00
Andy Miller
ca5819489f Fix for sandbox command 2015-12-02 12:38:56 -07:00
Matias Griese
1d2acf8096 Move onThemeInitialized event into Themes::initTheme() 2015-12-02 17:24:12 +02:00
Andy Miller
98278e965b Merge pull request #495 from tcsizmadia/develop
Updated Hungarian translation with new string.
2015-12-02 07:50:12 -07:00
Matias Griese
7bc990688c Add missing parent constructor to Themes class 2015-12-02 11:24:20 +02:00
Tamas Csizmadia
b86aa6d473 Updated Hungarian translation with new string. 2015-12-01 21:57:31 +01:00
Andy Miller
dba7347c1e Merge branch 'release/1.0.0-rc.6' 2015-12-01 13:13:16 -07:00
Andy Miller
fa52e18e3f Merge branch 'release/1.0.0-rc.6' into develop 2015-12-01 13:13:16 -07:00
Andy Miller
b605753a6d version update 2015-12-01 13:12:59 -07:00
Andy Miller
0af4fb351c changelog updated 2015-12-01 12:47:10 -07:00
Andy Miller
90edf95077 renamed LICENSE to LICENSE.txt 2015-12-01 11:15:00 -07:00
Andy Miller
ab3843442a Merge pull request #494 from getgrav/feature/introduce-user-groups
Feature/introduce user groups
2015-12-01 10:03:30 -07:00
Flavio Copes
023b9dd708 Merge remote-tracking branch 'origin/feature/introduce-user-groups' into feature/introduce-user-groups 2015-12-01 17:56:56 +01:00
Flavio Copes
0ac882314e Merge branch 'develop' into feature/introduce-user-groups 2015-12-01 17:54:20 +01:00
Flavio Copes
0fe9264582 Merge pull request #491 from MATsxm/patch-2
Update fr.yaml
2015-12-01 14:05:25 +01:00
Djamil Legato
b1e16b2206 Added validator for file input fields 2015-11-30 18:22:30 -08:00
Andy Miller
a67c1780c1 Added a new @self.all case that gets all children modular and non-modular 2015-11-30 19:16:46 -07:00
Marc-Antoine Thevenet
1170f2f58d Update fr.yaml
Update following the /en file
Thanks
2015-11-30 15:30:22 -04:00
Andy Miller
199c0a08ea Should not be able to set parent to self (infinite loop) #308 2015-11-30 12:18:32 -07:00
Matias Griese
84ad152536 Only create environmental config if the directory exists 2015-11-30 20:44:08 +02:00
Flavio Copes
5b0f905ae3 Update italian lang file 2015-11-30 19:20:20 +01:00
Flavio Copes
a2bba8f09d Merge pull request #489 from hugoaf/develop
Adding language string for MISSING_REQUIRED_FIELD
2015-11-30 19:19:51 +01:00
Matias Griese
2007975428 If environment does not have its own directory, remove it from the lookup 2015-11-30 10:13:40 -07:00
Matias Griese
e484997515 If environment does not have its own directory, remove it from the lookup 2015-11-30 18:56:34 +02:00
Flavio Copes
af5c52c52f Update session name hints 2015-11-30 14:36:23 +01:00
Hugo Avila
f3d0e10378 Update Blueprint.php 2015-11-29 21:43:05 -08:00
Hugo Avila
b33ab43ff9 Update en.yaml 2015-11-29 21:39:51 -08:00
Hugo Avila
c580399db6 Update es.yaml 2015-11-29 21:33:08 -08:00
Hugo Avila
00d8717d7c Create es.yaml 2015-11-29 21:26:21 -08:00
Andy Miller
6e2f4607a6 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-29 20:00:21 -07:00
Andy Miller
3a7abeb18b Added support to set classes and id on a medium object 2015-11-29 20:00:16 -07:00
Andy Miller
84a5984c65 Merge pull request #487 from aqnouch/patch-2
Change the first letter of the word 'français' to uppercase
2015-11-29 17:34:38 -07:00
AQNOUCH Mohammed
1465c26b1f Change the first letter of the word 'français' to uppercase 2015-11-28 19:20:59 +00:00
Flavio Copes
b399d8e3b9 Drop check used by the array field, introduced by 57b18edb55 2015-11-27 19:27:58 +01:00
Andy Miller
b5c04bdc9b Merge pull request #484 from nazwa/web.config-patch
Web.config update
2015-11-26 18:33:27 -07:00
Andy Miller
b4725800c3 Merge pull request #482 from diomed/patch-1
Update hr.yaml
2015-11-26 18:33:14 -07:00
nazwa
2b1a102efa Web.config update
web.config now correctly allows for static files inside vendor folder, just like .htaccess
2015-11-26 22:18:27 +00:00
Kruno H
500c548af4 Update hr.yaml
added PLURAL_MORE_THAN_TWO translations
2015-11-26 22:48:02 +01:00
Flavio Copes
fc7017f822 Merge pull request #480 from getgrav/feature/fix-set-time-limit
Include set_time_limit in a try/catch
2015-11-26 17:36:58 +01:00
Flavio Copes
5b254f4cf8 Drop accidentally added method 2015-11-26 16:19:29 +01:00
Flavio Copes
43783f3ce6 Correct the set_time_limit if 2015-11-26 16:18:05 +01:00
Flavio Copes
ae39aabee1 Include set_time_limit in a try/catch 2015-11-26 16:02:06 +01:00
Flavio Copes
df7a94148b Merge branch 'develop' into feature/introduce-user-groups 2015-11-26 12:14:48 +01:00
Flavio Copes
63890661fe Add security.yaml to the ignored files 2015-11-26 11:55:13 +01:00
Flavio Copes
793ac1a1bb Revert "no message"
This reverts commit b259927348.
2015-11-26 11:54:05 +01:00
Flavio Copes
77db54c50d Revert "If the page does not exist trigger a 404"
This reverts commit 8d8420c0d6.
2015-11-26 11:53:27 +01:00
Andy Miller
b259927348 no message 2015-11-25 15:42:11 -07:00
Andy Miller
e8972a6aa5 vendor updates 2015-11-25 15:41:53 -07:00
Flavio Copes
8d8420c0d6 If the page does not exist trigger a 404 2015-11-25 22:30:45 +01:00
Flavio Copes
7a6707f597 Merge pull request #473 from getgrav/feature/allow-multiple-plurals
Handle languages that support _PLURAL_MORE_THAN_TWO
2015-11-25 17:42:37 +01:00
Djamil Legato
b0ec66cce8 Merge pull request #475 from nazwa/lists-patch
Proper handling of list fields
2015-11-24 15:51:58 -08:00
Maciej Ka
edfd7db88b pretty & clean 2015-11-24 23:48:22 +00:00
Maciej Ka
fb3e68e16e removed old parameters 2015-11-24 23:34:47 +00:00
Maciej Ka
080ab9e289 Fixed conflict caused by w00fz quickfix 2015-11-24 23:17:37 +00:00
nazwa
f67e441b83 Merge pull request #1 from getgrav/develop
Fixed nested logic for lists and forms parsing (fixes #273)
2015-11-24 23:13:47 +00:00
nazwa
9c07d69c45 Proper handling of list fields
Moved field handling to a separate function and added logic to correctly process nested lists.
2015-11-24 23:02:42 +00:00
Djamil Legato
13207f13ad Fixed nested logic for lists and forms parsing (fixes #273) 2015-11-24 14:57:05 -08:00
Flavio Copes
34f83ebde2 Use the new security salt to calculate the nonce instead of using password_hash 2015-11-24 21:13:46 +01:00
Flavio Copes
14ed805656 Merge branch 'develop' into feature/introduce-user-groups 2015-11-24 21:00:08 +01:00
Matias Griese
385233c508 Automatically create unique security salt for each configuration 2015-11-24 21:14:46 +02:00
Flavio Copes
8a3b987cd5 Merge branch 'develop' into feature/introduce-user-groups 2015-11-24 19:45:04 +01:00
Andy Miller
bdd17fc56a Moving back to release version of Toolbox 2015-11-24 10:06:41 -07:00
Andy Miller
29b3c081ee Merge branch 'feature/refactor' into develop 2015-11-24 09:59:51 -07:00
Andy Miller
b1d80b6c5f Merge branch 'develop' into feature/refactor 2015-11-24 09:59:33 -07:00
Flavio Copes
e00560f81a Handle languages that support _PLURAL_MORE_THAN_TWO
Ex. WEEK_PLURAL, WEEK_PLURAL_MORE_THAN_TWO
2015-11-24 15:18:10 +01:00
Flavio Copes
20f17130a2 Add the IP address of the user to the nonce string calculation even if it's logged in 2015-11-24 15:17:08 +01:00
Flavio Copes
583156d2f3 Handle multiple nonce action types per page 2015-11-24 09:03:48 +01:00
Andy Miller
88f36f4987 Merge branch 'develop' into feature/refactor 2015-11-23 19:08:46 -07:00
Andy Miller
965c8cfbe9 Only generate one nonce per process 2015-11-23 19:07:46 -07:00
Andy Miller
b8f00243e6 Make hash() public for future use 2015-11-23 19:07:12 -07:00
Andy Miller
1d97f98515 Made hash() public for future usage 2015-11-23 17:41:16 -07:00
Matias Griese
9764cf3f65 Sync CompiledFile class with Gantry 2015-11-23 11:00:28 +02:00
Matias Griese
1f5df81496 Sync Folder class with Gantry 2015-11-23 11:00:03 +02:00
Matias Griese
5f76a0255c Merge branches 'develop' and 'feature/refactor' of https://github.com/getgrav/grav into feature/refactor
# Conflicts:
#	CHANGELOG.md
#	composer.lock
2015-11-23 09:48:30 +02:00
Flavio Copes
17f3ca6eba Merge pull request #466 from tcsizmadia/develop
Updated system/languages/hu.yaml
2015-11-22 16:32:57 +01:00
Tamas Csizmadia
b29d79738b Updated system/languages/hu.yaml
Tweaked translation for 'ago' - sounds less weird.
2015-11-22 12:34:44 +01:00
Andy Miller
020cdd7324 Merge pull request #464 from tcsizmadia/develop
Hungarian translation in system/languages/hu.yaml
2015-11-21 22:04:51 -07:00
Andy Miller
1e39f3b22d Merge pull request #465 from MAT978/patch-1
Update fr.yaml
2015-11-21 22:04:45 -07:00
Djamil Legato
37035a488d Fixed bin/plugin help output 2015-11-21 20:53:11 -08:00
Marc-Antoine Thevenet
745b418cd7 Update fr.yaml
update based on the version: en
Nov 17, 2015
2015-11-21 21:47:21 -04:00
Tamas Csizmadia
2a02c8bc4f Hungarian translation in system/languages/hu.yaml 2015-11-21 21:53:03 +01:00
Flavio Copes
a15e063b92 Merge branch 'develop' into feature/introduce-user-groups 2015-11-21 16:52:51 +01:00
Andy Miller
2051fed5b7 Merge pull request #458 from benblee/patch-1
Prevent crawling of unnecessary directories
2015-11-20 19:57:45 -07:00
Ben Lee
268714863e Prevent crawling of unnecessary directories
Prevent search engines from crawling and indexing unnecessary files and directories. The "/user/plugins/" directory may need to be added to the Allow list if plugins use frontend accessible assets. This is tested at a basic level using Google Fetch and Render.
2015-11-20 19:33:24 -07:00
Andy Miller
60c6532307 Merge branch 'release/1.0.0-rc.5' into develop 2015-11-20 17:54:40 -07:00
Andy Miller
50c6e81c09 Merge branch 'release/1.0.0-rc.5' 2015-11-20 17:54:39 -07:00
Andy Miller
2a0a9a225c version update 2015-11-20 17:54:28 -07:00
Andy Miller
aee92b58c7 Updated composer.phar 2015-11-20 17:34:34 -07:00
Andy Miller
16db950009 composer updates 2015-11-20 17:34:02 -07:00
Andy Miller
bde33e7188 Lighttpd/Lightly configuration file - Thanks @Mr3ase 2015-11-20 14:59:58 -07:00
Djamil Legato
267efbe164 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-20 12:40:52 -08:00
Djamil Legato
f9e137c994 Added pad filter for strings (uses str_pad) 2015-11-20 12:40:48 -08:00
Andy Miller
e7f9751403 add new Page.relativePagePath helper method 2015-11-20 08:08:39 -07:00
Matias Griese
9adf81294d Merge branches 'develop' and 'feature/refactor' of https://github.com/getgrav/grav into feature/refactor 2015-11-20 09:28:58 +02:00
Matias Griese
3033818589 On plaintext authentication verify, use default hash even if its not set in configuration 2015-11-20 09:22:07 +02:00
Djamil Legato
06d663680c Removed unused label 2015-11-19 20:05:29 -08:00
Djamil Legato
1bbdca5032 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-19 18:07:40 -08:00
Djamil Legato
c1654a988e Fixed deprecated message 2015-11-19 18:07:16 -08:00
Andy Miller
18a540c867 Don't set a default hash in system.yaml 2015-11-19 18:56:05 -07:00
Andy Miller
99fc8df322 old command was called newuser not new-user, also pointed to login plugin now. 2015-11-19 18:30:31 -07:00
Flavio Copes
2d21cb8b1e Simplify, clear slashes for all nonces automatically. Remove Utils:: getNonceForGetRequest methoid
The reason is, we need to get the nonce in JavaScript and we can simply
use the one in the form, made for POST requests
2015-11-19 23:23:32 +01:00
Flavio Copes
d8008654b9 Add a new Utils::getNonceForGetRequest() method, and use that in Uri:: addNonce() 2015-11-19 22:44:10 +01:00
Andy Miller
146295fb1e fix for state check if user was already logged in without state 2015-11-19 13:43:15 -07:00
Matias Griese
09ed480628 Composer update 2015-11-19 17:05:21 +02:00
Matias Griese
5dd1554e5d Fix modified function in config 2015-11-19 12:02:08 +02:00
Matias Griese
748f329c8e Merge branches 'develop' and 'feature/refactor' of https://github.com/getgrav/grav into feature/refactor
Conflicts:
	CHANGELOG.md
2015-11-19 10:51:26 +02:00
Matias Griese
7228b25393 Fix configuration reload 2015-11-19 10:49:55 +02:00
Djamil Legato
63e083ea37 Implemented new state check for accounts. If an account state is set to disabled no actions will be allowed 2015-11-18 18:31:19 -08:00
Andy Miller
b1630feb5d Disable time limit in case of slow downloads: #385 2015-11-18 19:04:57 -07:00
Andy Miller
1185a91c90 Fix for Media using absolute URLs internally causing breakages in functionality: #401 2015-11-18 18:39:30 -07:00
Andy Miller
dce6d7894b Added form blueprints for new append_url_extension field in system.yaml and page headers 2015-11-18 17:35:07 -07:00
Andy Miller
375ee0d1fa remove version from auto-generated generator tag 2015-11-18 17:17:53 -07:00
Andy Miller
ce0574f897 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-18 17:13:31 -07:00
Andy Miller
c515111446 Don't check valid media list if its' in whitelist 2015-11-18 17:13:22 -07:00
Djamil Legato
7d6393628e Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-18 16:12:12 -08:00
Djamil Legato
24fde7261a Deprecated: bin/grav new-user is now deprecated in favor of bin/plugin admin new-user 2015-11-18 16:12:08 -08:00
Djamil Legato
3d922abf1a Fixed listing duplicate plugins when multiple commands present. 2015-11-18 16:11:44 -08:00
Andy Miller
7f1d3a94fe Support default case of allowing all valid media types. Config option replaces with a whitelist of types supported. #452 2015-11-18 15:52:01 -07:00
Andy Miller
3d774b7585 moved fallback types to media 2015-11-18 15:50:46 -07:00
Djamil Legato
b0083548b6 Rearranged properly changelog entries 2015-11-18 11:55:34 -08:00
Djamil Legato
905dae3b16 Updated changelog 2015-11-18 11:51:16 -08:00
Djamil Legato
d79979371b Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-18 11:47:26 -08:00
Flavio Copes
c4bff94f7d Merge pull request #454 from diomed/patch-1
Croatian translation
2015-11-18 20:43:07 +01:00
Kruno H
7c4fd3858c Croatian translation 2015-11-18 20:35:23 +01:00
Djamil Legato
3b9af8883d Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-18 10:43:02 -08:00
Djamil Legato
29b34d7de0 Listing all plugins with CLI available. Better helper when empty arguments 2015-11-18 10:40:06 -08:00
Matias Griese
90fcf448c7 Merge branches 'develop' and 'feature/refactor' of https://github.com/getgrav/grav into feature/refactor 2015-11-18 18:17:33 +02:00
Flavio Copes
5193551d04 Fix date representation in system config
Fixes https://github.com/getgrav/grav-plugin-admin/issues/278
2015-11-18 17:15:18 +01:00
Matias Griese
d2660e0755 Fixed gzip compression making it to work correctly with all servers and browsers 2015-11-18 18:14:35 +02:00
Flavio Copes
2d8ac27fdd Merge pull request #451 from yaman-jain/docfixes
PhpDoc
2015-11-18 14:49:58 +01:00
Matias Griese
dd2ddfeb40 Refactor Config classes 2015-11-18 15:32:14 +02:00
Matias Griese
ac3396e6c4 Data objects: Allow function call chaining, lazy load blueprints 2015-11-18 14:43:32 +02:00
yaman-jain
49a5b38589 PhpDoc: callback definition as per #451 2015-11-18 16:01:19 +05:30
yaman-jain
6e2f792bb9 Merge branch 'develop' into docfixes 2015-11-18 15:55:25 +05:30
Djamil Legato
da098fd46a Implemented support for Plugins to hook into Grav CLI via bin/plugin <plugin-name> 2015-11-17 19:33:55 -08:00
Djamil Legato
3e081b340f Cleaned up Console commands, now extending Grav's own ConsoleCommand class 2015-11-17 19:31:13 -08:00
Djamil Legato
698015a03d Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-17 19:12:45 -08:00
Djamil Legato
000a10f936 Added check in Plugins::get method to ensure a plugin exists 2015-11-17 18:36:08 -08:00
Flavio Copes
c764e31c8a Merge pull request #448 from bovisp/patch-3
Added form validation translations
2015-11-17 22:32:38 +01:00
Flavio Copes
c18021d52a Merge pull request #450 from bovisp/patch-2
Added a translation for "Invalid input in " text
2015-11-17 22:32:15 +01:00
Flavio Copes
3d0cc67415 Merge pull request #449 from bovisp/patch-1
Added a translation for "Validation failed:" text
2015-11-17 22:32:00 +01:00
Paul Bovis
3f94a6fda9 moved $language variable inside catch statement
As requested
2015-11-17 14:25:51 -07:00
yaman-jain
7f0eefbde5 updated/added PhpDoc for methods 2015-11-18 02:32:44 +05:30
Paul Bovis
280377985f Added form validation translations
These will need to be translated into other languages.
2015-11-17 11:57:15 -07:00
Paul Bovis
d5b3f070a5 Added a translation for "Invalid input in " text
The English phrase "Invalid input in " was hardcoded at line 40. I created a new translation 'FORM.INVALID_INPUT' and placed it in /system/languages/en.yaml. It will need to be translated into other languages by others.
2015-11-17 11:55:31 -07:00
Paul Bovis
3505ef046d Added a translation for "Validation failed:" text
The English term "Validation failed:" was hard coded on line 83. Instead, I created a translation and placed this at /system/languages/en.yaml. It will need to be translated into other languages by others.
2015-11-17 11:50:47 -07:00
Flavio Copes
a6bc565356 Replace forward slashes automatically to avoid problems when used in GET request 2015-11-17 11:59:30 +01:00
Flavio Copes
a1ee3cf4e4 Avoid using our own hash, let PHP use its own for password_hash, fix #445 2015-11-17 11:59:02 +01:00
Andy Miller
e96445abe3 Added append_url_extension option to system/page headers. 2015-11-16 21:33:24 -07:00
Andy Miller
c22fae0d3d just added a comment 2015-11-16 21:33:01 -07:00
Flavio Copes
d888dcd085 Add some methods to ImageMedium to be used by the media manager 2015-11-16 20:15:47 +01:00
Flavio Copes
184cb9ea3a Media Meta blueprint 2015-11-16 20:15:19 +01:00
Flavio Copes
3cf6e8762c Merge pull request #426 from getgrav/feature/nonce
Add nonce functionality
2015-11-13 19:18:29 +01:00
Flavio Copes
f0cdd7c03e Merge branch 'develop' into feature/nonce 2015-11-13 18:24:03 +01:00
Andy Miller
5e40201888 Merge pull request #441 from yaman-jain/removePackageInterface
PackageInterface was deleted #435
2015-11-13 11:03:08 -06:00
Flavio Copes
f2c2debb28 Fix exception message when label is not set 2015-11-13 17:50:04 +01:00
Matias Griese
997c772b7c Make Data classes to implement proper interfaces 2015-11-13 14:09:03 +02:00
Matias Griese
bc4a09f80d Fix undefined variable in Config class 2015-11-13 14:02:06 +02:00
Andy Miller
0e3e7497ac Fix for https://github.com/getgrav/grav-plugin-form/issues/17 2015-11-12 18:31:15 -07:00
Andy Miller
72313ac9ec Merge branch 'feature/new-imagemedium-methods' into develop 2015-11-12 17:40:21 -07:00
yaman-jain
dc80228f0b PackageInterface was deleted #435 2015-11-13 00:48:54 +05:30
Flavio Copes
a83642a7e3 Added a higherQualityAlternative () method to get the highest quality image available (3x or 2x) 2015-11-12 19:15:26 +01:00
Flavio Copes
00d8403095 Allow to get the image quality in addition to setting it 2015-11-12 19:14:52 +01:00
Matias Griese
e1ec8e9742 Fix undefined variable in Config class 2015-11-12 20:09:23 +02:00
Flavio Copes
0725af5367 Handle case login plugin disabled (thanks @hwmaier) 2015-11-12 09:17:22 +01:00
Andy Miller
65e543af02 Merge pull request #434 from yaman-jain/feature/smallfixes
remove duplicate key
2015-11-11 18:24:29 -07:00
Andy Miller
b49e8315eb Merge pull request #439 from enko/patch-1
Use PCRE_UTF8 so unicode strings don't break up.
2015-11-12 00:42:45 +01:00
Tim
c5a89112b4 Use PCRE_UTF8 so unicode strings don't break up.
The `Truncator`-class fails when the truncated text contains unicode characters with a nice exception:

    "DOMDocumentFragment::appendXML(): Entity: line 1: parser error : Input is not proper UTF-8, indicate encoding ! Bytes: 0xC3 0xE2 0x80 0xA6"

By using the `PCRE_UTF8` modifier `u` everything is UTF8 and all is fine.
2015-11-12 00:13:21 +01:00
Flavio Copes
94ec474ffa Merge branch 'develop' into feature/nonce 2015-11-11 17:47:57 +01:00
Flavio Copes
da4593fdc1 Drop commented referrer code 2015-11-11 17:13:54 +01:00
Flavio Copes
b8413cefaf Avoid having to deal with slashes in URLs 2015-11-10 17:34:23 +01:00
Flavio Copes
d3097e4fd0 Merge pull request #433 from Sommerregen/patch-3
Fixes #432 (Theme autoloading doesn't seem to work)
2015-11-10 14:32:14 +01:00
yaman-jain
51753f0716 remove unused 'use' statements 2015-11-10 18:24:01 +05:30
yaman-jain
b7ada873b8 remove duplicate key 2015-11-10 17:34:01 +05:30
Benny
ed8b08a9e4 Fixes #432 (Theme autoloading doesn't seem to work) 2015-11-10 11:19:30 +01:00
Flavio Copes
e1fdb6803d Add nonce functionality 2015-11-06 15:31:49 +01:00
Andy Miller
5cb9f2f42f Merge pull request #419 from hwmaier/feature/empty-inline-assets
Don't create <style> or <script> tags for empty inline CSS or inline JS
2015-11-06 10:08:10 +05:30
Flavio Copes
fcf48ed2e5 Merge pull request #420 from bariscelik/develop
added "Turkish" language
2015-11-05 09:16:36 +01:00
Barış ÇELİK
050512536a added "Turkish" language 2015-11-05 08:42:24 +03:00
Henrik Maier
99207fca13 Don't create <style> or <script> tags for empty inline CSS or inline JS 2015-11-05 13:37:06 +10:00
Flavio Copes
55890b4fd8 Merge branch 'develop' into feature/introduce-user-groups 2015-11-04 14:54:56 +01:00
Flavio Copes
6fdfaccc92 Add blueprints 2015-11-04 14:54:47 +01:00
Flavio Copes
76e01e7aea Minor fix 2015-11-04 14:44:21 +01:00
Flavio Copes
87378562ea Fix error when logging in with a non-existing username 2015-11-03 14:35:11 +01:00
Andy Miller
77d80f12f3 Fix for untranslated validation messages #246 2015-11-02 17:28:46 -07:00
Flavio Copes
e400207a65 Fix https://github.com/getgrav/grav-plugin-admin/issues/249, password not required any more. If not set, it's not changed. If set, it's changed (if it satisfies the requirements) 2015-11-02 18:57:16 +01:00
Andy Miller
4b68036a1b Fixed assets stream for bin/grav clear 2015-11-01 20:52:14 -07:00
Henrik Maier
a95b716aa7 Return resource even if not physically present 2015-11-01 19:43:54 -07:00
Henrik Maier
dc8efded34 Use streams instead of hardcoded paths for clearCache() 2015-11-01 19:43:53 -07:00
Andy Miller
e016b17276 Revert "Use streams instead of hardcoded paths for clearCache()"
This reverts commit a86ce7cb28.
2015-11-01 19:24:46 -07:00
Andy Miller
b99876f0b4 Revert "Return resource even if not physically present"
This reverts commit b3144ee921.
2015-11-01 19:24:39 -07:00
Andy Miller
66abc842b7 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-11-01 18:34:41 -07:00
Andy Miller
9f36158c67 Merge pull request #405 from hwmaier/feature/trailing-slash
Added support for default routes with a trailing slash
2015-11-01 18:34:31 -07:00
Andy Miller
18c1ca3919 added 'theme' to config containing current theme configuration so now possible to just to {{ config.theme.dropdown_enabled }} #406 2015-11-01 18:32:55 -07:00
Andy Miller
0c729e5b0a latest vendor updates 2015-11-01 13:56:10 -07:00
Andy Miller
55f3b78ab1 Merge pull request #393 from hwmaier/feature/image-height-width
Support for width/height and style attributes to media and image files
2015-11-01 09:43:28 -07:00
Andy Miller
a73b796ca7 Merge pull request #407 from hwmaier/feature/enable-progressive-bug
Clear previously applied operations when doing a reset on image files to avoid calling filters twice
2015-11-01 09:42:29 -07:00
Andy Miller
bb0bca7ef1 Merge pull request #408 from hwmaier/feature/clear-cache
Use streams instead of hardcoded paths for clearCache()
2015-11-01 08:53:54 -07:00
Henrik Maier
b3144ee921 Return resource even if not physically present 2015-11-01 18:55:33 +10:00
Henrik Maier
a86ce7cb28 Use streams instead of hardcoded paths for clearCache() 2015-11-01 17:50:23 +10:00
Henrik Maier
ccf2a780b6 Clear previously applied operations when doing a reset on image files 2015-11-01 10:26:56 +10:00
Henrik Maier
b0c1dbe4b7 Added support for default routes with a trailing slash 2015-10-31 16:21:05 +10:00
Djamil Legato
ec73eef695 Updated comments for subfolders 2015-10-30 10:49:08 -07:00
Andy Miller
467d68344e added a default umask_fix property to system.yaml 2015-10-30 11:42:36 -06:00
Andy Miller
8899b3ebb8 Rewrote nginx.conf to be simpler and more in line with .htaccess 2015-10-30 11:42:08 -06:00
Andy Miller
5478cfaf9f Improved .htaccess security 2015-10-30 11:41:52 -06:00
Andy Miller
4b6a85f30a updated vendor libs 2015-10-30 11:41:03 -06:00
Andy Miller
e62ff07726 Merge branch 'release/1.0.0-rc.4' 2015-10-29 22:11:19 -06:00
Andy Miller
a045107cc7 Merge branch 'release/1.0.0-rc.4' into develop 2015-10-29 22:11:19 -06:00
Andy Miller
c97edb60a5 version update 2015-10-29 22:11:06 -06:00
Andy Miller
695793b752 Merge branch 'release/1.0.0-rc.4' 2015-10-29 21:53:48 -06:00
Andy Miller
c953ffb471 Merge branch 'release/1.0.0-rc.4' into develop 2015-10-29 21:53:48 -06:00
Andy Miller
3d7fa06129 version update 2015-10-29 21:52:52 -06:00
Andy Miller
49d4fbcf3d fix for non-existing page with collection @page: /something format 2015-10-29 21:50:58 -06:00
Andy Miller
fc18a40c35 fixed double bang 2015-10-29 20:03:19 -06:00
Andy Miller
1e81d5e38c whitespace tweak 2015-10-29 16:34:30 -06:00
Andy Miller
daf8b53c0d Merge branch 'release/1.0.0-rc.3' into develop 2015-10-29 14:08:39 -06:00
Andy Miller
8de55a745d Merge branch 'release/1.0.0-rc.3' 2015-10-29 14:08:38 -06:00
Andy Miller
6bf669815d version update 2015-10-29 14:08:09 -06:00
Andy Miller
8ba49e163d version update 2015-10-29 14:06:54 -06:00
Andy Miller
26918d90ab Merge pull request #397 from Sommerregen/patch-2
Addresses # 12 (form-plugin) Trim fields before validation
2015-10-29 11:57:11 -06:00
Benny
929b0806dc Addresses # 12 (form-plugin) Trim fields before validation 2015-10-29 16:58:41 +01:00
Flavio Copes
3e32e61db1 Revert "Add a items() method that returns the Data::items array"
This reverts commit fafd72fcd8.
2015-10-29 14:59:11 +01:00
Flavio Copes
038693bffb Merge pull request #396 from Sommerregen/patch-1
Fix #395
2015-10-29 14:00:54 +01:00
Benny
9445aa43e6 Fix #395 (Problem with default language and slugs that is starting with language name) 2015-10-29 13:44:29 +01:00
Henrik Maier
bb16dbab78 Remove debug error_log output 2015-10-29 13:02:22 +10:00
Andy Miller
658212e7be Merge pull request #392 from nickbalestra/readme
Update README.md
2015-10-28 21:01:56 -06:00
Nick Balestra
e91554770c Update README.md 2015-10-28 19:58:38 -07:00
Henrik Maier
8f9671ad32 Allow width and height attributes to be added to Markdown and Twig image tags 2015-10-29 12:53:00 +10:00
Andy Miller
7f134e39f4 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2015-10-28 20:52:30 -06:00
Henrik Maier
c87e3f419d Allow inline styles to be added to Markdown and Twig image tags 2015-10-29 12:52:24 +10:00
Andy Miller
07b2767ac9 Changed collection types from .recurse to .descendants 2015-10-28 20:52:22 -06:00
Andy Miller
0ca24a9786 Merge pull request #391 from tuphamnguyen/patch-1
Updated README.md
2015-10-28 20:39:58 -06:00
Tu Pham Nguyen
c84c1366e7 Updated README.md
Just a typo :)
2015-10-28 16:25:29 -05:00
Andy Miller
ebf9bb5c18 Improved collection support #384 2015-10-28 13:33:35 -06:00
Andy Miller
70b67a0805 Created whitelist for fallback route functionality 2015-10-28 10:39:15 -06:00
Andy Miller
545b97716f Merge pull request #387 from hwmaier/feature/asset-stream
Asset management uses now streams rather the constant ASSETS_DIR
2015-10-28 10:12:54 -06:00
Flavio Copes
7e540e0623 Merge branch 'develop' into feature/introduce-user-groups
Use the new isPositive() method to check permissions
2015-10-28 11:00:48 +01:00
Flavio Copes
f7140522f6 Merge pull request #388 from littmus/develop
Typo fixed
2015-10-28 09:56:02 +01:00
littmus
bd2f7088e9 Typo fixed 2015-10-28 17:55:23 +09:00
hwmaier
5260c181a1 Asset management uses now streams rather the constant ASSETS_DIR to configure location. In addition it supports subdirectories for assets location, for example assets/runtime. 2015-10-28 13:15:03 +10:00
Andy Miller
a9538adf2b Merge branch 'release/1.0.0-rc.2' into develop 2015-10-27 14:47:43 -06:00
Andy Miller
8bba0fd332 Merge branch 'release/1.0.0-rc.2' 2015-10-27 14:47:43 -06:00
Andy Miller
abf6d6638e version update 2015-10-27 14:47:27 -06:00
Andy Miller
36e52146f5 changelog updated 2015-10-27 12:35:29 -06:00
Flavio Copes
24eaa24839 Check that label is set prior to access it 2015-10-27 18:30:54 +01:00
Flavio Copes
fafd72fcd8 Add a items() method that returns the Data::items array 2015-10-27 18:30:54 +01:00
Andy Miller
df9b219a16 Merge pull request #386 from hwmaier/feature/onTwigPageVariables
onTwigPageVariables event handler gets Page object passed as Event parameter
2015-10-27 09:49:47 -06:00
hwmaier
5c9c378889 onTwigPageVariables event handler gets Page object passed 2015-10-27 23:04:21 +10:00
Andy Miller
47e1eab6c1 updated bundled composer.phar 2015-10-26 17:31:48 -06:00
Andy Miller
d88f56316d updated changelog 2015-10-26 17:15:25 -06:00
Andy Miller
8b414c388d wrapped_site option in system.yaml 2015-10-26 17:14:58 -06:00
Flavio Copes
acb828eacf Merge pull request #382 from tbreuss/develop
Use of capital and small initial letters
2015-10-26 20:40:31 +01:00
Thomas Breuss
293dfad87e Use of capital and small initial letters 2015-10-26 19:35:08 +01:00
Andy Miller
e4e1927126 Merge pull request #381 from getgrav/feature/check-positive-value
Check a positive value, not just "true"
2015-10-26 11:53:31 -06:00
Flavio Copes
edf6f86cb5 Add a Utils::isPositive(). Use that. 2015-10-26 18:29:22 +01:00
Flavio Copes
d086664a61 Check a positive value, not just "true" 2015-10-26 18:06:28 +01:00
Flavio Copes
b0c171f453 Merge branch 'develop' into feature/introduce-user-groups 2015-10-26 17:48:53 +01:00
Andy Miller
feed15f75b changelog update 2015-10-25 18:46:07 -06:00
Andy Miller
95fd54d909 Moved grav variable into globals and removed from template variables 2015-10-25 16:49:28 -06:00
Andy Miller
79f6380aae improved merging of meta tags into title/alt/class 2015-10-25 16:43:52 -06:00
Andy Miller
8478d690a0 Optimizations to the TAG regex handling for inline CSS/JS 2015-10-25 16:20:01 -06:00
Andy Miller
5db8197db2 use a regex to remove surrounding tags but not inline ones! #376 2015-10-24 22:35:44 -06:00
Andy Miller
8407e5b295 Metadata return a new Data object so nulls are possible #375 2015-10-24 16:01:22 -06:00
Andy Miller
3e3b4548e9 Fix for inline JS and HTML entities #376 2015-10-24 15:21:25 -06:00
Andy Miller
868a61dd34 Fail quietly if file doesn't exist 2015-10-24 14:53:16 -06:00
Andy Miller
a7a5625a8b Revert "Added CSS Group asset support #374"
This reverts commit f65633043a.
2015-10-24 12:19:47 -06:00
Andy Miller
a614c8c7cc Added CSS Group asset support #374 2015-10-24 12:19:22 -06:00
Andy Miller
f65633043a Added CSS Group asset support #374 2015-10-24 12:18:54 -06:00
Djamil Legato
de61d88d29 Synced travis.yml 2015-10-23 16:11:26 -07:00
Djamil Legato
9d86c0a9db Merge tag '1.0.0-rc.1' into develop
Release v1.0.0-rc.1
2015-10-23 14:44:38 -07:00
Flavio Copes
67fefb53ad Allow to filter pages by access level 2015-10-21 19:47:06 +02:00
Flavio Copes
0ff5dc0016 Add accessLevels to return the used page access levels 2015-10-21 18:41:34 +02:00
Flavio Copes
ae17a77789 Use config/groups.yaml instead of config/site.yaml 2015-10-21 17:47:39 +02:00
Flavio Copes
5f11ae7482 Allow editing user groups from user form 2015-10-21 12:28:36 +02:00
Flavio Copes
4d33eb2173 Add access to account blueprint 2015-10-21 12:22:04 +02:00
Flavio Copes
fe7873ddbe Allow to remove a group 2015-10-21 12:21:53 +02:00
Flavio Copes
f95a4f5cc6 Move resolve() to Utils. 2015-10-21 12:21:47 +02:00
Flavio Copes
f973b61b5e Change how permissions work: if true in group, but false in user, false has precedence (allows to fine tune removing permissions per-user) 2015-10-21 12:21:23 +02:00
Flavio Copes
f1d4192ae7 Introduce a resolve() function to Utils, used by Group and User to access an array using dot notation 2015-10-21 12:20:45 +02:00
Flavio Copes
fb500d3e1c Handle saving a new group 2015-10-21 11:09:29 +02:00
Flavio Copes
14347ebf88 Group object 2015-10-20 19:31:47 +02:00
Flavio Copes
3e0188e40b Group blueprint 2015-10-20 19:31:25 +02:00
Flavio Copes
b82f17f367 First draft of group blueprints 2015-10-20 16:36:25 +02:00
Flavio Copes
3f28dc59ea Add check 2015-10-20 16:07:04 +02:00
Flavio Copes
77deea8ad4 Allow a user to be assigned to multiple groups 2015-10-20 15:58:07 +02:00
Flavio Copes
e27f638fe3 The User authorize method now checks first if the user group the user belongs to has permissions for the resource (single group version) 2015-10-19 20:15:11 +02:00
151 changed files with 5121 additions and 2499 deletions

4
.gitignore vendored
View File

@@ -16,12 +16,15 @@ logs/*
!logs/.* !logs/.*
images/* images/*
!images/.* !images/.*
user/accounts/*
!user/accounts/.*
user/data/* user/data/*
!user/data/.* !user/data/.*
user/plugins/* user/plugins/*
!user/plugins/.* !user/plugins/.*
user/themes/* user/themes/*
!user/themes/.* !user/themes/.*
user/localhost/config/security.yaml
# OS Generated # OS Generated
.DS_Store* .DS_Store*
@@ -32,3 +35,4 @@ Thumbs.db
# phpstorm # phpstorm
.idea/* .idea/*
user/config/security.yaml

View File

@@ -44,15 +44,17 @@ RewriteRule .* index.php [L]
## Begin - Security ## Begin - Security
# Block all direct access for these folders # Block all direct access for these folders
RewriteRule ^(.git|cache|bin|logs|backup)/(.*) error [L] RewriteRule ^(.git|cache|bin|logs|backup|webserver-configs)/(.*) error [F]
# Block access to specific file types for these folders # Block access to specific file types for these system folders
RewriteRule ^(system|user|vendor)/(.*)\.(txt|md|html|yaml|php|twig|sh|bat)$ error [L] RewriteRule ^(system|vendor)/(.*)\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$ error [F]
# Block access to specific file types for these user folders
RewriteRule ^(user)/(.*)\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ error [F]
# Block all direct access to .md files: # Block all direct access to .md files:
RewriteRule \.md$ error [L] RewriteRule \.md$ error [F]
# Block all direct access to files and folders beginning with a dot # Block all direct access to files and folders beginning with a dot
RewriteRule (^\.|/\.) - [F] RewriteRule (^\.|/\.) - [F]
# Block access to specific files in the root folder # Block access to specific files in the root folder
RewriteRule ^(LICENSE|composer.lock|composer.json|nginx.conf|web.config)$ error [F] RewriteRule ^(LICENSE.txt|composer.lock|composer.json|\.htaccess)$ error [F]
## End - Security ## End - Security
</IfModule> </IfModule>

View File

@@ -40,8 +40,10 @@ env:
- TRAVIS_TAG=$(curl --fail --user ${GH_API_USER} -s https://api.github.com/repos/getgrav/grav/releases/latest | grep tag_name | head -n 1 | cut -d '"' -f 4) - TRAVIS_TAG=$(curl --fail --user ${GH_API_USER} -s https://api.github.com/repos/getgrav/grav/releases/latest | grep tag_name | head -n 1 | cut -d '"' -f 4)
before_install: before_install:
- export TZ=Pacific/Honolulu
- composer self-update - composer self-update
- go get github.com/aktau/github-release - go get github.com/aktau/github-release
- echo "Travis Date - `date`"
- git clone --quiet --depth=50 --branch=master https://${BB_TOKEN}bitbucket.org/rockettheme/grav-devtools.git $RT_DEVTOOLS &>/dev/null; - git clone --quiet --depth=50 --branch=master https://${BB_TOKEN}bitbucket.org/rockettheme/grav-devtools.git $RT_DEVTOOLS &>/dev/null;
- if [ ! -z "$TRAVIS_TAG" ]; then - if [ ! -z "$TRAVIS_TAG" ]; then
cd "${RT_DEVTOOLS}"; cd "${RT_DEVTOOLS}";
@@ -52,7 +54,11 @@ script:
FILES="$RT_DEVTOOLS/grav-dist/*.zip"; FILES="$RT_DEVTOOLS/grav-dist/*.zip";
for file in ${FILES[@]}; do for file in ${FILES[@]}; do
NAME=${file##*/}; NAME=${file##*/};
REPO="$(echo ${NAME} | rev | cut -f 2- -d "-" | rev)"; if [[ "$NAME" == *"-rc"* ]]; then
REPO="$(echo ${NAME} | rev | cut -f 3- -d "-" | rev)";
else
REPO="$(echo ${NAME} | rev | cut -f 2- -d "-" | rev)";
fi;
if [[ $REPO == 'grav' || $REPO == 'grav-admin' || $REPO == 'grav-update' ]]; then if [[ $REPO == 'grav' || $REPO == 'grav-admin' || $REPO == 'grav-update' ]]; then
REPO="grav"; REPO="grav";
fi; fi;
@@ -60,7 +66,7 @@ script:
ASSETS="$(echo "${API}" | node gh-assets.js)"; ASSETS="$(echo "${API}" | node gh-assets.js)";
TAG="$(echo "${API}" | grep tag_name | head -n 1 | cut -d '"' -f 4)"; TAG="$(echo "${API}" | grep tag_name | head -n 1 | cut -d '"' -f 4)";
if [ $REPO == "grav" ]; then if [ $REPO == "grav" ]; then
TAG=$TRAVIS_TAG; TAG="$TRAVIS_TAG";
fi; fi;
if [ ! -z "$ASSETS" ]; then if [ ! -z "$ASSETS" ]; then
for asset in ${ASSETS[@]}; do for asset in ${ASSETS[@]}; do

View File

@@ -1,3 +1,245 @@
# v1.0.8
## 01/08/2016
1. [](#new)
* Added `rotate`, `flip` and `fixOrientation` image medium methods
1. [](#bugfix)
* Removed IP from Nonce generation. Should be more reliably in a variety of scenarios
# v1.0.7
## 01/07/2016
1. [](#new)
* Added `composer create-project` as an additional installation method #585
* New optional system config setting to strip home from page routs and urls #561
* Added Greek, Finnish, Norwegian, Polish, Portuguese, and Romanian languages
* Added new `Page->topParent()` method to return top most parent of a page
* Added plugins configuration tab to debugger
* Added support for APCu and PHP7.0 via new Doctrine Cache release
* Added global setting for `twig_first` processing (false by default)
* New configuration options for Session settings #553
1. [](#improved)
* Switched to SSL for GPM calls
* Use `URI->host()` for session domain
* Add support for `open_basedir` when installing packages via GPM
* Improved `Utils::generateNonceString()` method to handle reverse proxies
* Optimized core thumbnails saving 38% in file size
* Added new `bin/gpm index --installed-only` option
* Improved GPM errors to provider more helpful diagnostic of issues
* Removed old hardcoded PHP version references
* Moved `onPageContentProcessed()` event so it's fired more reliably
* Maintain md5 keys during sorting of Assets #566
* Update to Caddyfile for Caddy web server
1. [](#bugfix)
* Fixed an issue with cache/config checksum not being set on cache load
* Fix for page blueprint and theme inheritance issue #534
* Set `ZipBackup` timeout to 10 minutes if possible
* Fix case where we only have inline data for CSS or JS #565
* Fix `bin/grav sandbox` command to work with new `webserver-config` folder
* Fix for markdown attributes on external URLs
* Fixed issue where `data:` page header was acting as `publish_date:`
* Fix for special characters in URL parameters (e.g. /tag:c++) #541
* Safety check for an array of nonces to only use the first one
# v1.0.6
## 12/22/2015
1. [](#new)
* Set minimum requirements to [PHP 5.5.9](http://bit.ly/1Jt9OXO)
* Added `saveConfig` to Themes
1. [](#improved)
* Updated Whoops to new 2.0 version (PHP 7.0 compatible)
* Moved sample web server configs into dedicated directory
* FastCGI will use Apache's `mod_deflate` if gzip turned off
1. [](#bugfix)
* Fix broken media image operators
* Only call extra method of blueprints if blueprints exist
* Fix lang prefix in url twig variables #523
* Fix case insensitive HTTPS check #535
* Field field validation handles case `multiple` missing
# v1.0.5
## 12/18/2015
1. [](#new)
* Add ability to extend markdown with plugins
* Added support for plugins to have individual language files
* Added `7z` to media formats
* Use Grav's fork of Parsedown until PR is merged
* New function to persist plugin configuration to disk
* GPM `selfupgrade` will now check PHP version requirements
1. [](#improved)
* If the field allows multiple files, return array
* Handle non-array values in file validation
1. [](#bugfix)
* Fix when looping `fields` param in a `list` field
* Properly convert commas to spaces for media attributes
* Forcing Travis VM to HI timezone to address future files in zip file
# v1.0.4
## 12/12/2015
1. [](#bugfix)
* Needed to put default image folder permissions for YAML compatibility
# v1.0.3
## 12/11/2015
1. [](#bugfix)
* Fixed issue when saving config causing incorrect image cache folder perms
# v1.0.2
## 12/11/2015
1. [](#bugfix)
* Fix for timing display in debugbar
# v1.0.1
## 12/11/2015
1. [](#improved)
* Reduced package sizes by removing extra vendor dev bits
1. [](#bugfix)
* Fix issue when you enable debugger from admin plugin
# 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
1. [](#new)
* Added **nonce** functionality for all admin forms for improved security
* 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 `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
* Added new `|pad` Twig filter for strings (uses `str_pad()`)
* Added `lighttpd.conf` for Lightly web server
1. [](#improved)
* Clear previously applied operations when doing a reset on image media
* Password no longer required when editing user
* Improved support for trailing `/` URLs
* Improved `.nginx.conf` configuration file
* Improved `.htaccess` security
* Updated vendor libs
* Updated `composer.phar`
* Use streams instead of paths for `clearCache()`
* Use PCRE_UTF8 so unicode strings can be regexed in Truncator
* Handle case when login plugin is disabled
* Improved `quality` functionality in media handling
* Added some missing translation strings
* Deprecated `bin/grav newuser` in favor of `bin/plugin login new-user`
* Moved fallback types to use any valid media type
* Renamed `system.pages.fallback_types` to `system.media.allowed_fallback_types`
* Removed version number in default `generator` meta tag
* Disable time limit in case of slow downloads
* Removed default hash in `system.yaml`
1. [](#bugfix)
* Fix for media using absolute URLs causing broken links
* Fix theme auto-loading #432
* Don't create empty `<style>` or `<script>` scripts if no data
* Code cleanups
* Fix undefined variable in Config class
* Fix exception message when label is not set
* Check in `Plugins::get()` to ensure plugins exists
* Fixed GZip compression making output buffering work correctly with all servers and browsers
* Fixed date representation in system config
# v1.0.0-rc.4
## 10/29/2015
1. [](#bugfix)
* Fixed a fatal error if you have a collection with missing or invalid `@page: /route`
# v1.0.0-rc.3
## 10/29/2015
1. [](#new)
* New Page collection options! `@self.parent, @self.siblings, @self.descendants` + more
* White list of file types for fallback route functionality (images by default)
1. [](#improved)
* Assets switched from defines to streams
1. [](#bugfix)
* README.md typos fixed
* Fixed issue with routes that have lang string in them (`/en/english`)
* Trim strings before validation so whitespace is not satisfy 'required'
# v1.0.0-rc.2
## 10/27/2015
1. [](#new)
* Added support for CSS Asset groups
* Added a `wrapped_site` system option for themes/plugins to use
* Pass `Page` object as event to `onTwigPageVariables()` event hook
* New `Data.items()` method to get all items
1. [](#improved)
* Missing pipelined remote asset will now fail quietly
* More reliably handle inline JS and CSS to remove only surrounding HTML tags
* `Medium.meta` returns new Data object so null checks are possible
* Improved Medium metadata merging to allow for automatic title/alt/class attributes
* Moved Grav object to global variable rather than template variable (useful for macros)
* German language improvements
* Updated bundled composer
1. [](#bugfix)
* Accept variety of `true` values in `User.authorize()` method
* Fix for `Validation` throwing an error if no label set
# v1.0.0-rc.1 # v1.0.0-rc.1
## 10/23/2015 ## 10/23/2015
@@ -18,7 +260,7 @@
1. [](#improved) 1. [](#improved)
* Moved hardcoded mimetypes to `media.yaml` to be treated as Page media files * Moved hardcoded mimetypes to `media.yaml` to be treated as Page media files
* Set `errors: display: false` by default in `system.yaml` * Set `errors: display: false` by default in `system.yaml`
* Strip out extra slashes in the URI * Strip out extra slashes in the URI
* Validate hostname to ensure it is valid * Validate hostname to ensure it is valid
* Ignore more SCM folders in Backups * Ignore more SCM folders in Backups
* Removed `home_redirect` settings from `system.yaml` * Removed `home_redirect` settings from `system.yaml`
@@ -29,7 +271,7 @@
* Debugbar vendor library update * Debugbar vendor library update
* Always fallback to english if other translations are not available * Always fallback to english if other translations are not available
1. [](#bugfix) 1. [](#bugfix)
* Fix for redirecting external URL with multi-language * Fix for redirecting external URL with multi-language
* Fix for Asset pipeline not respecting asset groups * Fix for Asset pipeline not respecting asset groups
* Fix language files with child/parent theme relationships * Fix language files with child/parent theme relationships
* Fixed a regression issue resulting in incorrect default language * Fixed a regression issue resulting in incorrect default language

122
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,122 @@
# Contributing to Grav
:+1::tada: First, thanks for getting involved with Grav! :tada::+1:
Please take a moment to review this document in order to make the contribution
process easy and effective for everyone involved.
Following these guidelines helps to communicate that you respect the time of
the developers managing and developing this open source project. In return,
they should reciprocate that respect in addressing your issue or assessing
patches and features.
## Grav, Plugins, Themes and Skeletons
Grav is a large open source project—it's made up of over 100 repositories. When you initially consider contributing to Grav, you might be unsure about which of those 200 repositories implements the functionality you want to change or report a bug for.
[https://github.com/getgrav/grav](https://github.com/getgrav/grav) is the main Grav repository. The core of Grav is provided by this repo.
[https://github.com/getgrav/grav-plugin-admin](https://github.com/getgrav/grav-plugin-admin) is the Admin Plugin repository.
Every Plugin and Theme has its own repository. If you have a problem you think is specific to a Theme or Plugin, please report it in its corresponding repository. Please read the Plugin or Theme documentation to ensure the problem is not addressed there already.
Every Skeleton also has its own repository, so if an issue is not specific to a theme or plugin but rather to its usage in the skeleton, report it in the skeleton repository.
## Using the issue tracker
The issue tracker is the preferred channel for [bug reports](#bugs),
[features requests](#features) and [submitting pull
requests](#pull-requests), but please respect the following restrictions:
* Please **do not** use the issue tracker for support requests. Use
[the Forum](http://getgrav.org/forum) or [the Gitter chat](https://gitter.im/getgrav/grav).
<a name="bugs"></a>
## Bug reports
A bug is a _demonstrable problem_ that is caused by the code in the repository.
Good bug reports are extremely helpful - thank you!
Guidelines for bug reports:
1. **Check you satisfy the Grav requirements** &mdash; [http://learn.getgrav.org/basics/requirements](http://learn.getgrav.org/basics/requirements)
2. **Check this happens on a clean Grav install** &mdash; check if the issue happens on any Grav site, or just with a specific configuration of plugins / theme
3. **Use the GitHub issue search** &mdash; check if the issue has already been
reported.
4. **Check if the issue is already being solved in a PR** &mdash; check the open Pull Requests to see if one already solves the problem you're having
5. **Check if the issue has been fixed** &mdash; try to reproduce it using the
latest `develop` branch in the repository.
6. **Isolate the problem** &mdash; create a [reduced test
case](http://css-tricks.com/reduced-test-cases/) and provide a step-by-step instruction set on how to recreate the problem. Include code samples, page snippets or yaml configurations if needed.
A good bug report shouldn't leave others needing to chase you up for more
information. Please try to be as detailed as possible in your report.
What is your environment? Is it localhost, OSX, Linux, on a remote server? Same happening locally and or the server, or just locally or just on Linux?
What steps will reproduce the issue? What browser(s) and OS experience the problem?
What would you expect to be the outcome?
Did the problem start happening recently (e.g. after updating to a new version of Grav) or was this always a problem?
If the problem started happening recently, can you reproduce the problem in an older version of Grav? What's the most recent version in which the problem doesn't happen? You can download older versions of Grav from the releases page on Github.
Can you reliably reproduce the issue? If not, provide details about how often the problem happens and under which conditions it normally happens.
All these details will help people to fix any potential bugs.
Important: [include Code Samples in triple backticks](https://help.github.com/articles/github-flavored-markdown/#fenced-code-blocks) so that Github will provide a proper indentation. [Add the language name after the backticks](https://help.github.com/articles/github-flavored-markdown/#syntax-highlighting) to add syntax highlighting to the code snippets.
Example:
> Short and descriptive example bug report title
>
> A summary of the issue and the browser/OS environment in which it occurs. If
> suitable, include the steps required to reproduce the bug.
>
> 1. This is the first step
> 2. This is the second step
> 3. Further steps, etc.
>>
> Any other information you want to share that is relevant to the issue being
> reported. This might include the lines of code that you have identified as
> causing the bug, and potential solutions (and your opinions on their
> merits).
<a name="features"></a>
## Feature requests
Feature requests are welcome. But take a moment to find out whether your idea
fits with the scope and aims of the project. It's up to *you* to make a strong
case to convince the project's developers of the merits of this feature. Please
provide as much detail and context as possible.
<a name="pull-requests"></a>
## Pull requests
Good pull requests - patches, improvements, new features - are a fantastic
help. They should remain focused in scope and avoid containing unrelated
commits.
**Please ask first** in Gitter or in the Forum before embarking on any significant pull request (e.g.
implementing features, refactoring code..),
otherwise you risk spending a lot of time working on something that the
project's developers might not want to merge into the project.
Please adhere to the coding conventions used throughout the project (indentation,
accurate comments, etc.) and any other requirements.
See [Using Pull Request](https://help.github.com/articles/using-pull-requests/) and [Fork a Repo](https://help.github.com/articles/fork-a-repo/) if you're not familiar with Pull Requests.
**IMPORTANT**: By submitting a patch, you agree to allow the project owner to
license your work under the same license as that used by the project.

View File

@@ -9,26 +9,34 @@ The underlying architecture of Grav is designed to use well-established and _bes
* [Twig Templating](http://twig.sensiolabs.org/): for powerful control of the user interface * [Twig Templating](http://twig.sensiolabs.org/): for powerful control of the user interface
* [Markdown](http://en.wikipedia.org/wiki/Markdown): for easy content creation * [Markdown](http://en.wikipedia.org/wiki/Markdown): for easy content creation
* [YAML](http://yaml.org): for simple configuration * [YAML](http://yaml.org): for simple configuration
* [Parsedown](http://parsedown.org/): for fast Markdown and Mardown Extra support * [Parsedown](http://parsedown.org/): for fast Markdown and Markdown Extra support
* [Doctrine Cache](http://docs.doctrine-project.org/en/2.0.x/reference/caching.html): layer for performance * [Doctrine Cache](http://docs.doctrine-project.org/en/2.0.x/reference/caching.html): layer for performance
* [Pimple Dependency Injection Container](http://pimple.sensiolabs.org/): for extensibility and maintainability * [Pimple Dependency Injection Container](http://pimple.sensiolabs.org/): for extensibility and maintainability
* [Symfony Event Dispacher](http://symfony.com/doc/current/components/event_dispatcher/introduction.html): for plugin event handling * [Symfony Event Dispatcher](http://symfony.com/doc/current/components/event_dispatcher/introduction.html): for plugin event handling
* [Symfony Console](http://symfony.com/doc/current/components/console/introduction.html): for CLI interface * [Symfony Console](http://symfony.com/doc/current/components/console/introduction.html): for CLI interface
* [Gregwar Image Library](https://github.com/Gregwar/Image): for dynamic image manipulation * [Gregwar Image Library](https://github.com/Gregwar/Image): for dynamic image manipulation
# Requirements # Requirements
- PHP 5.4 or higher. Check the [required modules list](http://learn.getgrav.org/basics/requirements#php-requirements) - PHP 5.5.9 or higher. Check the [required modules list](http://learn.getgrav.org/basics/requirements#php-requirements)
- Check the [Apache](http://learn.getgrav.org/basics/requirements#apache-requirements) or [IIS](http://learn.getgrav.org/basics/requirements#iis-requirements) requirements - Check the [Apache](http://learn.getgrav.org/basics/requirements#apache-requirements) or [IIS](http://learn.getgrav.org/basics/requirements#iis-requirements) requirements
# QuickStart # QuickStart
You have two options to get Grav: These are the options to get Grav:
### Downloading a Grav Package ### Downloading a Grav Package
You can download a **ready-built** package from the [Downloads page on http://getgrav.org](http://getgrav.org/downloads) You can download a **ready-built** package from the [Downloads page on http://getgrav.org](http://getgrav.org/downloads)
### With composer
You can create a new project with the latest **stable** Grav release with the following command:
```
$ composer create-project getgrav/grav ~/webroot/grav
```
### From GitHub ### From GitHub
1. Clone the Grav repository from [https://github.com/getgrav/grav]() to a folder in the webroot of your server, e.g. `~/webroot/grav`. Launch a **terminal** or **console** and navigate to the webroot folder: 1. Clone the Grav repository from [https://github.com/getgrav/grav]() to a folder in the webroot of your server, e.g. `~/webroot/grav`. Launch a **terminal** or **console** and navigate to the webroot folder:
@@ -53,7 +61,7 @@ You can download [plugins](http://getgrav.org/downloads/plugins) or [themes](htt
$ bin/gpm index $ bin/gpm index
``` ```
This will display all the available plugins and then you can install one ore more with: This will display all the available plugins and then you can install one or more with:
``` ```
$ bin/gpm install <plugin/theme> $ bin/gpm install <plugin/theme>
@@ -76,7 +84,7 @@ $ bin/gpm update
# Contributing # Contributing
We appreciate any contribution to Grav, whether it is related to bugs, grammar, or simply a suggestion or improvement. We appreciate any contribution to Grav, whether it is related to bugs, grammar, or simply a suggestion or improvement.
However, we ask that any contribution follow our simple guidelines in order to be properly received. However, we ask that any contributions follow our simple guidelines in order to be properly received.
All our projects follow the [GitFlow branching model][gitflow-model], from development to release. If you are not familiar with it, there are several guides and tutorials to make you understand what it is about. All our projects follow the [GitFlow branching model][gitflow-model], from development to release. If you are not familiar with it, there are several guides and tutorials to make you understand what it is about.
@@ -103,7 +111,7 @@ What you mainly want to know is that:
# License # License
See [LICENSE](LICENSE) See [LICENSE](LICENSE.txt)
[gitflow-model]: http://nvie.com/posts/a-successful-git-branching-model/ [gitflow-model]: http://nvie.com/posts/a-successful-git-branching-model/

Binary file not shown.

10
bin/gpm
View File

@@ -2,10 +2,6 @@
<?php <?php
define('GRAV_CLI', true); define('GRAV_CLI', true);
if (version_compare($ver = PHP_VERSION, $req = '5.4.0', '<')) {
exit(sprintf("You are running PHP %s, but Grav needs at least PHP %s to run.\n", $ver, $req));
}
if (!file_exists(__DIR__ . '/../vendor')){ if (!file_exists(__DIR__ . '/../vendor')){
require_once __DIR__ . '/../system/src/Grav/Common/Composer.php'; require_once __DIR__ . '/../system/src/Grav/Common/Composer.php';
} }
@@ -25,6 +21,10 @@ use Grav\Common\Grav;
$autoload = require_once(__DIR__ . '/../vendor/autoload.php'); $autoload = require_once(__DIR__ . '/../vendor/autoload.php');
if (version_compare($ver = PHP_VERSION, $req = GRAV_PHP_MIN, '<')) {
exit(sprintf("You are running PHP %s, but Grav needs at least PHP %s to run.\n", $ver, $req));
}
if (!ini_get('date.timezone')) { if (!ini_get('date.timezone')) {
date_default_timezone_set('UTC'); date_default_timezone_set('UTC');
} }
@@ -40,8 +40,6 @@ if (!function_exists('curl_version')) {
$grav = Grav::instance(array('loader' => $autoload)); $grav = Grav::instance(array('loader' => $autoload));
$grav['config']->init(); $grav['config']->init();
$grav['streams']; $grav['streams'];
$grav['plugins']->init();
$grav['themes']->init();
$app = new Application('Grav Package Manager', GRAV_VERSION); $app = new Application('Grav Package Manager', GRAV_VERSION);
$app->addCommands(array( $app->addCommands(array(

View File

@@ -2,10 +2,6 @@
<?php <?php
define('GRAV_CLI', true); define('GRAV_CLI', true);
if (version_compare($ver = PHP_VERSION, $req = '5.4.0', '<')) {
exit(sprintf("You are running PHP %s, but Grav needs at least PHP %s to run.\n", $ver, $req));
}
if (!file_exists(__DIR__ . '/../vendor')){ if (!file_exists(__DIR__ . '/../vendor')){
require_once __DIR__ . '/../system/src/Grav/Common/Composer.php'; require_once __DIR__ . '/../system/src/Grav/Common/Composer.php';
} }
@@ -24,6 +20,10 @@ use Symfony\Component\Console\Application;
require_once __DIR__ . '/../vendor/autoload.php'; require_once __DIR__ . '/../vendor/autoload.php';
if (version_compare($ver = PHP_VERSION, $req = GRAV_PHP_MIN, '<')) {
exit(sprintf("You are running PHP %s, but Grav needs at least PHP %s to run.\n", $ver, $req));
}
if (!ini_get('date.timezone')) { if (!ini_get('date.timezone')) {
date_default_timezone_set('UTC'); date_default_timezone_set('UTC');
} }

116
bin/plugin Executable file
View File

@@ -0,0 +1,116 @@
#!/usr/bin/env php
<?php
define('GRAV_CLI', true);
if (!file_exists(__DIR__ . '/../vendor')) {
require_once __DIR__ . '/../system/src/Grav/Common/Composer.php';
}
use Grav\Common\Composer;
if (!file_exists(__DIR__ . '/../vendor')) {
// Before we can even start, we need to run composer first
$composer = Composer::getComposerExecutor();
echo "Preparing to install vendor dependencies...\n\n";
echo system($composer . ' --working-dir="' . __DIR__ . '/../" --no-interaction --no-dev --prefer-dist -o install');
echo "\n\n";
}
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Grav\Common\Grav;
use Grav\Common\Filesystem\Folder;
$autoload = require_once(__DIR__ . '/../vendor/autoload.php');
if (version_compare($ver = PHP_VERSION, $req = GRAV_PHP_MIN, '<')) {
exit(sprintf("You are running PHP %s, but Grav needs at least PHP %s to run.\n", $ver, $req));
}
if (!ini_get('date.timezone')) {
date_default_timezone_set('UTC');
}
if (!file_exists(ROOT_DIR . 'index.php')) {
exit('FATAL: Must be run from ROOT directory of Grav!');
}
$grav = Grav::instance(array('loader' => $autoload));
$grav['config']->init();
$grav['streams'];
$grav['plugins']->init();
$grav['themes']->init();
$app = new Application('Grav Plugins Commands', GRAV_VERSION);
$pattern = '([A-Z]\w+Command\.php)';
// get arguments and strip the application name
if (null === $argv) {
$argv = $_SERVER['argv'];
}
$bin = array_shift($argv);
$name = array_shift($argv);
$argv = array_merge([$bin], $argv);
$input = new ArgvInput($argv);
$plugin = $grav['plugins']->get($name);
$output = new ConsoleOutput();
$output->getFormatter()->setStyle('red', new OutputFormatterStyle('red', null, array('bold')));
$output->getFormatter()->setStyle('white', new OutputFormatterStyle('white', null, array('bold')));
if (!$name) {
$output->writeln('');
$output->writeln("<red>Usage:</red>");
$output->writeln(" {$bin} [slug] [command] [arguments]");
$output->writeln('');
$output->writeln("<red>Example:</red>");
$output->writeln(" {$bin} error log -l 1 --trace");
$list = Folder::all('plugins://', ['compare' => 'Pathname', 'pattern' => '/\/cli\/' . $pattern . '$/usm']);
if (count($list)) {
$available = [];
$output->writeln('');
$output->writeln('<red>Plugins with CLI available:</red>');
foreach ($list as $index => $entry) {
$split = explode('/', $entry);
$entry = array_shift($split);
$index = str_pad($index++ + 1, 2, '0', STR_PAD_LEFT);
if (in_array($entry, $available)) {
continue;
}
$available[] = $entry;
$output->writeln(' ' . $index . ". <red>" . str_pad($entry, 15) . "</red> <white>${bin} ${entry} list</white>");
}
}
exit;
}
if ($plugin === null) {
$output->writeln("<red>Grav Plugin <white>'{$name}'</white> is not installed</red>");
exit;
}
$path = 'plugins://' . $name . '/cli';
try {
$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;
}
foreach ($commands as $command) {
require_once "plugins://{$name}/cli/{$command}";
$command = 'Grav\Plugin\Console\\' . preg_replace('/.php$/', '', $command);
$app->add(new $command());
}
$app->run($input);

View File

@@ -1,29 +1,36 @@
{ {
"name": "getgrav/grav", "name": "getgrav/grav",
"type": "library", "type": "project",
"description": "Modern, Crazy Fast, Ridiculously Easy and Amazingly Powerful Flat-File CMS", "description": "Modern, Crazy Fast, Ridiculously Easy and Amazingly Powerful Flat-File CMS",
"keywords": ["cms","flat-file cms","flat cms","flatfile cms","php"], "keywords": ["cms","flat-file cms","flat cms","flatfile cms","php"],
"homepage": "http://getgrav.org", "homepage": "http://getgrav.org",
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": ">=5.4.0", "php": ">=5.5.9",
"twig/twig": "~1.16", "twig/twig": "~1.23",
"erusev/parsedown-extra": "~0.7", "erusev/parsedown-extra": "~0.7",
"symfony/yaml": "~2.7", "symfony/yaml": "~2.8",
"symfony/console": "~2.7", "symfony/console": "~2.8",
"symfony/event-dispatcher": "~2.7", "symfony/event-dispatcher": "~2.8",
"symfony/var-dumper": "~2.7", "symfony/var-dumper": "~2.8",
"doctrine/cache": "~1.4", "symfony/polyfill-iconv": "~1.0",
"filp/whoops": "1.2.*@dev", "doctrine/cache": "~1.5",
"filp/whoops": "2.0.0-alpha2",
"monolog/monolog": "~1.0", "monolog/monolog": "~1.0",
"gregwar/image": "~2.0", "gregwar/image": "~2.0",
"ircmaxell/password-compat": "1.0.*", "ircmaxell/password-compat": "1.0.*",
"mrclay/minify": "~2.2", "mrclay/minify": "~2.2",
"donatj/phpuseragentparser": "~0.3", "donatj/phpuseragentparser": "~0.3",
"pimple/pimple": "~3.0", "pimple/pimple": "~3.0",
"rockettheme/toolbox": "1.1.*", "rockettheme/toolbox": "~1.2",
"maximebf/debugbar": "~1.10" "maximebf/debugbar": "~1.10"
}, },
"repositories": [
{
"type": "vcs",
"url": "https://github.com/getgrav/parsedown"
}
],
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Grav\\": "system/src/Grav" "Grav\\": "system/src/Grav"
@@ -32,5 +39,13 @@
}, },
"archive": { "archive": {
"exclude": ["VERSION"] "exclude": ["VERSION"]
},
"scripts": {
"post-create-project-cmd": "bin/grav install"
},
"extra": {
"branch-alias": {
"dev-develop": "1.x-dev"
}
} }
} }

343
composer.lock generated
View File

@@ -1,45 +1,46 @@
{ {
"_readme": [ "_readme": [
"This file locks the dependencies of your project to a known state", "This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "e1db721096772d41f16003b39b47c85a", "hash": "85173a1bfa9ece106f687d69402d99d8",
"content-hash": "410b016e6cd8af6cd8ee9cdb6d5fd7a4",
"packages": [ "packages": [
{ {
"name": "doctrine/cache", "name": "doctrine/cache",
"version": "v1.4.2", "version": "v1.6.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/cache.git", "url": "https://github.com/doctrine/cache.git",
"reference": "8c434000f420ade76a07c64cbe08ca47e5c101ca" "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/8c434000f420ade76a07c64cbe08ca47e5c101ca", "url": "https://api.github.com/repos/doctrine/cache/zipball/f8af318d14bdb0eff0336795b428b547bd39ccb6",
"reference": "8c434000f420ade76a07c64cbe08ca47e5c101ca", "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.2" "php": "~5.5|~7.0"
}, },
"conflict": { "conflict": {
"doctrine/common": ">2.2,<2.4" "doctrine/common": ">2.2,<2.4"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": ">=3.7", "phpunit/phpunit": "~4.8|~5.0",
"predis/predis": "~1.0", "predis/predis": "~1.0",
"satooshi/php-coveralls": "~0.6" "satooshi/php-coveralls": "~0.6"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.5.x-dev" "dev-master": "1.6.x-dev"
} }
}, },
"autoload": { "autoload": {
"psr-0": { "psr-4": {
"Doctrine\\Common\\Cache\\": "lib/" "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@@ -74,7 +75,7 @@
"cache", "cache",
"caching" "caching"
], ],
"time": "2015-08-31 12:36:41" "time": "2015-12-31 16:37:02"
}, },
{ {
"name": "donatj/phpuseragentparser", "name": "donatj/phpuseragentparser",
@@ -132,12 +133,12 @@
"version": "1.6.0", "version": "1.6.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/erusev/parsedown.git", "url": "https://github.com/getgrav/parsedown.git",
"reference": "3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7" "reference": "3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7", "url": "https://api.github.com/repos/getgrav/parsedown/zipball/3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7",
"reference": "3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7", "reference": "3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7",
"shasum": "" "shasum": ""
}, },
@@ -147,7 +148,6 @@
"Parsedown": "" "Parsedown": ""
} }
}, },
"notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
"MIT" "MIT"
], ],
@@ -164,20 +164,23 @@
"markdown", "markdown",
"parser" "parser"
], ],
"support": {
"source": "https://github.com/getgrav/parsedown/tree/1.6.0"
},
"time": "2015-10-04 16:44:32" "time": "2015-10-04 16:44:32"
}, },
{ {
"name": "erusev/parsedown-extra", "name": "erusev/parsedown-extra",
"version": "0.7.0", "version": "0.7.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/erusev/parsedown-extra.git", "url": "https://github.com/erusev/parsedown-extra.git",
"reference": "11a44e076d02ffcc4021713398a60cd73f78b6f5" "reference": "0db5cce7354e4b76f155d092ab5eb3981c21258c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown-extra/zipball/11a44e076d02ffcc4021713398a60cd73f78b6f5", "url": "https://api.github.com/repos/erusev/parsedown-extra/zipball/0db5cce7354e4b76f155d092ab5eb3981c21258c",
"reference": "11a44e076d02ffcc4021713398a60cd73f78b6f5", "reference": "0db5cce7354e4b76f155d092ab5eb3981c21258c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -208,40 +211,45 @@
"parsedown", "parsedown",
"parser" "parser"
], ],
"time": "2015-01-25 14:52:34" "time": "2015-11-01 10:19:22"
}, },
{ {
"name": "filp/whoops", "name": "filp/whoops",
"version": "dev-master", "version": "2.0.0-alpha2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/filp/whoops.git", "url": "https://github.com/filp/whoops.git",
"reference": "9a393ceb80f7497b6513feb574638e87048fed55" "reference": "eb1ce6439db161a9f00cd57f33a9cfa1355229ec"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/9a393ceb80f7497b6513feb574638e87048fed55", "url": "https://api.github.com/repos/filp/whoops/zipball/eb1ce6439db161a9f00cd57f33a9cfa1355229ec",
"reference": "9a393ceb80f7497b6513feb574638e87048fed55", "reference": "eb1ce6439db161a9f00cd57f33a9cfa1355229ec",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.0" "php": ">=5.5.9"
}, },
"require-dev": { "require-dev": {
"mockery/mockery": "0.9.*" "mockery/mockery": "0.9.*",
"phpunit/phpunit": "^4.8 || ^5.0"
},
"suggest": {
"symfony/var-dumper": "Pretty print complex values better with var-dumper available",
"whoops/soap": "Formats errors as SOAP responses"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.2-dev" "dev-master": "2.0-dev"
} }
}, },
"autoload": { "autoload": {
"psr-0": { "psr-4": {
"Whoops": "src/" "Whoops\\": "src/Whoops/"
}, },
"classmap": [ "files": [
"src/deprecated" "src/Whoops/functions.php"
] ]
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@@ -262,11 +270,10 @@
"exception", "exception",
"handling", "handling",
"library", "library",
"silex-provider",
"whoops", "whoops",
"zf2" "zf2"
], ],
"time": "2015-09-27 09:47:06" "time": "2015-12-15 12:27:17"
}, },
{ {
"name": "gregwar/cache", "name": "gregwar/cache",
@@ -403,25 +410,25 @@
}, },
{ {
"name": "maximebf/debugbar", "name": "maximebf/debugbar",
"version": "v1.10.5", "version": "v1.11.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/maximebf/php-debugbar.git", "url": "https://github.com/maximebf/php-debugbar.git",
"reference": "30e53e8a28284b69dd223c9f5ee8957befd72636" "reference": "07741d84d39d10f00551c94284cdefcc69703e77"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/30e53e8a28284b69dd223c9f5ee8957befd72636", "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/07741d84d39d10f00551c94284cdefcc69703e77",
"reference": "30e53e8a28284b69dd223c9f5ee8957befd72636", "reference": "07741d84d39d10f00551c94284cdefcc69703e77",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.0", "php": ">=5.3.0",
"psr/log": "~1.0", "psr/log": "^1.0",
"symfony/var-dumper": "~2.6" "symfony/var-dumper": "^2.6|^3.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "~4.0" "phpunit/phpunit": "^4.0|^5.0"
}, },
"suggest": { "suggest": {
"kriswallsmith/assetic": "The best way to manage assets", "kriswallsmith/assetic": "The best way to manage assets",
@@ -431,12 +438,12 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.10-dev" "dev-master": "1.11-dev"
} }
}, },
"autoload": { "autoload": {
"psr-0": { "psr-4": {
"DebugBar": "src/" "DebugBar\\": "src/DebugBar/"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@@ -448,14 +455,19 @@
"name": "Maxime Bouroumeau-Fuseau", "name": "Maxime Bouroumeau-Fuseau",
"email": "maxime.bouroumeau@gmail.com", "email": "maxime.bouroumeau@gmail.com",
"homepage": "http://maximebf.com" "homepage": "http://maximebf.com"
},
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
} }
], ],
"description": "Debug bar in the browser for php application", "description": "Debug bar in the browser for php application",
"homepage": "https://github.com/maximebf/php-debugbar", "homepage": "https://github.com/maximebf/php-debugbar",
"keywords": [ "keywords": [
"debug" "debug",
"debugbar"
], ],
"time": "2015-10-19 20:35:12" "time": "2015-12-10 09:50:24"
}, },
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
@@ -665,16 +677,16 @@
}, },
{ {
"name": "rockettheme/toolbox", "name": "rockettheme/toolbox",
"version": "1.1.4", "version": "1.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/rockettheme/toolbox.git", "url": "https://github.com/rockettheme/toolbox.git",
"reference": "ff677d8f66d1addd3590d0cb85bcbaff4174d9c9" "reference": "0c7a3b4b6e4d73be8512e89f7acde6899334b7f2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/rockettheme/toolbox/zipball/ff677d8f66d1addd3590d0cb85bcbaff4174d9c9", "url": "https://api.github.com/repos/rockettheme/toolbox/zipball/0c7a3b4b6e4d73be8512e89f7acde6899334b7f2",
"reference": "ff677d8f66d1addd3590d0cb85bcbaff4174d9c9", "reference": "0c7a3b4b6e4d73be8512e89f7acde6899334b7f2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -710,30 +722,30 @@
"php", "php",
"rockettheme" "rockettheme"
], ],
"time": "2015-10-15 23:27:40" "time": "2015-11-24 17:04:24"
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v2.7.5", "version": "v2.8.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "06cb17c013a82f94a3d840682b49425cd00a2161" "reference": "2e06a5ccb19dcf9b89f1c6a677a39a8df773635a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/06cb17c013a82f94a3d840682b49425cd00a2161", "url": "https://api.github.com/repos/symfony/console/zipball/2e06a5ccb19dcf9b89f1c6a677a39a8df773635a",
"reference": "06cb17c013a82f94a3d840682b49425cd00a2161", "reference": "2e06a5ccb19dcf9b89f1c6a677a39a8df773635a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.9" "php": ">=5.3.9",
"symfony/polyfill-mbstring": "~1.0"
}, },
"require-dev": { "require-dev": {
"psr/log": "~1.0", "psr/log": "~1.0",
"symfony/event-dispatcher": "~2.1", "symfony/event-dispatcher": "~2.1|~3.0.0",
"symfony/phpunit-bridge": "~2.7", "symfony/process": "~2.1|~3.0.0"
"symfony/process": "~2.1"
}, },
"suggest": { "suggest": {
"psr/log": "For using the console logger", "psr/log": "For using the console logger",
@@ -743,13 +755,16 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.7-dev" "dev-master": "2.8-dev"
} }
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Symfony\\Component\\Console\\": "" "Symfony\\Component\\Console\\": ""
} },
"exclude-from-classmap": [
"/Tests/"
]
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
@@ -767,20 +782,20 @@
], ],
"description": "Symfony Console Component", "description": "Symfony Console Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2015-09-25 08:32:23" "time": "2015-12-22 10:25:57"
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",
"version": "v2.7.5", "version": "v2.8.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/event-dispatcher.git", "url": "https://github.com/symfony/event-dispatcher.git",
"reference": "ae4dcc2a8d3de98bd794167a3ccda1311597c5d9" "reference": "a5eb815363c0388e83247e7e9853e5dbc14999cc"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ae4dcc2a8d3de98bd794167a3ccda1311597c5d9", "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a5eb815363c0388e83247e7e9853e5dbc14999cc",
"reference": "ae4dcc2a8d3de98bd794167a3ccda1311597c5d9", "reference": "a5eb815363c0388e83247e7e9853e5dbc14999cc",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -788,11 +803,10 @@
}, },
"require-dev": { "require-dev": {
"psr/log": "~1.0", "psr/log": "~1.0",
"symfony/config": "~2.0,>=2.0.5", "symfony/config": "~2.0,>=2.0.5|~3.0.0",
"symfony/dependency-injection": "~2.6", "symfony/dependency-injection": "~2.6|~3.0.0",
"symfony/expression-language": "~2.6", "symfony/expression-language": "~2.6|~3.0.0",
"symfony/phpunit-bridge": "~2.7", "symfony/stopwatch": "~2.3|~3.0.0"
"symfony/stopwatch": "~2.3"
}, },
"suggest": { "suggest": {
"symfony/dependency-injection": "", "symfony/dependency-injection": "",
@@ -801,13 +815,16 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.7-dev" "dev-master": "2.8-dev"
} }
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Symfony\\Component\\EventDispatcher\\": "" "Symfony\\Component\\EventDispatcher\\": ""
} },
"exclude-from-classmap": [
"/Tests/"
]
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
@@ -825,27 +842,146 @@
], ],
"description": "Symfony EventDispatcher Component", "description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2015-09-22 13:49:29" "time": "2015-10-30 20:15:42"
}, },
{ {
"name": "symfony/var-dumper", "name": "symfony/polyfill-iconv",
"version": "v2.7.5", "version": "v1.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/var-dumper.git", "url": "https://github.com/symfony/polyfill-iconv.git",
"reference": "ba8c9a0edf18f70a7efcb8d3eb35323a10263338" "reference": "541cce29a46d6ee18bb9271c6ac3ca783b0faab0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/ba8c9a0edf18f70a7efcb8d3eb35323a10263338", "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/541cce29a46d6ee18bb9271c6ac3ca783b0faab0",
"reference": "ba8c9a0edf18f70a7efcb8d3eb35323a10263338", "reference": "541cce29a46d6ee18bb9271c6ac3ca783b0faab0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.9" "php": ">=5.3.3"
},
"suggest": {
"ext-iconv": "For best performance"
},
"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-20 09:19:13"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "49ff736bd5d41f45240cec77b44967d76e0c3d25"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/49ff736bd5d41f45240cec77b44967d76e0c3d25",
"reference": "49ff736bd5d41f45240cec77b44967d76e0c3d25",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"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-20 09:19:13"
},
{
"name": "symfony/var-dumper",
"version": "v2.8.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "f943f29ae69c42511a2d85adee9d13d835b5c803"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/f943f29ae69c42511a2d85adee9d13d835b5c803",
"reference": "f943f29ae69c42511a2d85adee9d13d835b5c803",
"shasum": ""
},
"require": {
"php": ">=5.3.9",
"symfony/polyfill-mbstring": "~1.0"
}, },
"require-dev": { "require-dev": {
"symfony/phpunit-bridge": "~2.7" "twig/twig": "~1.20|~2.0"
}, },
"suggest": { "suggest": {
"ext-symfony_debug": "" "ext-symfony_debug": ""
@@ -853,7 +989,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.7-dev" "dev-master": "2.8-dev"
} }
}, },
"autoload": { "autoload": {
@@ -862,7 +998,10 @@
], ],
"psr-4": { "psr-4": {
"Symfony\\Component\\VarDumper\\": "" "Symfony\\Component\\VarDumper\\": ""
} },
"exclude-from-classmap": [
"/Tests/"
]
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
@@ -884,38 +1023,38 @@
"debug", "debug",
"dump" "dump"
], ],
"time": "2015-09-22 14:41:01" "time": "2015-12-05 11:09:21"
}, },
{ {
"name": "symfony/yaml", "name": "symfony/yaml",
"version": "v2.7.5", "version": "v2.8.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/yaml.git", "url": "https://github.com/symfony/yaml.git",
"reference": "31cb2ad0155c95b88ee55fe12bc7ff92232c1770" "reference": "ac84cbb98b68a6abbc9f5149eb96ccc7b07b8966"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/31cb2ad0155c95b88ee55fe12bc7ff92232c1770", "url": "https://api.github.com/repos/symfony/yaml/zipball/ac84cbb98b68a6abbc9f5149eb96ccc7b07b8966",
"reference": "31cb2ad0155c95b88ee55fe12bc7ff92232c1770", "reference": "ac84cbb98b68a6abbc9f5149eb96ccc7b07b8966",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.9" "php": ">=5.3.9"
}, },
"require-dev": {
"symfony/phpunit-bridge": "~2.7"
},
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.7-dev" "dev-master": "2.8-dev"
} }
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Symfony\\Component\\Yaml\\": "" "Symfony\\Component\\Yaml\\": ""
} },
"exclude-from-classmap": [
"/Tests/"
]
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
@@ -933,20 +1072,20 @@
], ],
"description": "Symfony Yaml Component", "description": "Symfony Yaml Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2015-09-14 14:14:09" "time": "2015-12-26 13:37:56"
}, },
{ {
"name": "twig/twig", "name": "twig/twig",
"version": "v1.22.3", "version": "v1.23.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/twigphp/Twig.git", "url": "https://github.com/twigphp/Twig.git",
"reference": "ebfc36b7e77b0c1175afe30459cf943010245540" "reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/ebfc36b7e77b0c1175afe30459cf943010245540", "url": "https://api.github.com/repos/twigphp/Twig/zipball/d9b6333ae8dd2c8e3fd256e127548def0bc614c6",
"reference": "ebfc36b7e77b0c1175afe30459cf943010245540", "reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -959,7 +1098,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.22-dev" "dev-master": "1.23-dev"
} }
}, },
"autoload": { "autoload": {
@@ -994,19 +1133,19 @@
"keywords": [ "keywords": [
"templating" "templating"
], ],
"time": "2015-10-13 07:07:02" "time": "2015-11-05 12:49:06"
} }
], ],
"packages-dev": [], "packages-dev": [],
"aliases": [], "aliases": [],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": { "stability-flags": {
"filp/whoops": 20 "filp/whoops": 15
}, },
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": ">=5.4.0" "php": ">=5.5.9"
}, },
"platform-dev": [] "platform-dev": []
} }

View File

@@ -1,9 +1,6 @@
<?php <?php
namespace Grav; namespace Grav;
if (version_compare($ver = PHP_VERSION, $req = '5.4.0', '<')) {
throw new \RuntimeException(sprintf('You are running PHP %s, but Grav needs at least <strong>PHP %s</strong> to run.', $ver, $req));
}
// Ensure vendor libraries exist // Ensure vendor libraries exist
$autoload = __DIR__ . '/vendor/autoload.php'; $autoload = __DIR__ . '/vendor/autoload.php';
@@ -16,6 +13,10 @@ use Grav\Common\Grav;
// Register the auto-loader. // Register the auto-loader.
$loader = require_once $autoload; $loader = require_once $autoload;
if (version_compare($ver = PHP_VERSION, $req = GRAV_PHP_MIN, '<')) {
throw new \RuntimeException(sprintf('You are running PHP %s, but Grav needs at least <strong>PHP %s</strong> to run.', $ver, $req));
}
// Set timezone to default, falls back to system if php.ini not set // Set timezone to default, falls back to system if php.ini not set
date_default_timezone_set(@date_default_timezone_get()); date_default_timezone_set(@date_default_timezone_get());

View File

@@ -1,87 +0,0 @@
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location / {
root html;
index index.php;
if (!-e $request_filename){ rewrite ^(.*)$ /index.php last; }
}
# if you want grav in a sub-directory of your main site
# (for example, example.com/mygrav) then you need this rewrite:
location /mygrav {
index index.php;
if (!-e $request_filename){ rewrite ^(.*)$ /mygrav/$2 last; }
try_files $uri $uri/ /index.php?$args;
}
# if using grav in a sub-directory of your site,
# prepend the actual path to each location
# for example: /mygrav/images
# and: /mygrav/user
# and: /mygrav/cache
# and so on
location /images/ {
# Serve images as static
}
location /user {
rewrite ^/user/accounts/(.*)$ /error redirect;
rewrite ^/user/config/(.*)$ /error redirect;
rewrite ^/user/(.*)\.(txt|md|html|php|yaml|json|twig|sh|bat)$ /error redirect;
}
location /cache {
rewrite ^/cache/(.*) /error redirect;
}
location /bin {
rewrite ^/bin/(.*)$ /error redirect;
}
location /backup {
rewrite ^/backup/(.*) /error redirect;
}
location /system {
rewrite ^/system/(.*)\.(txt|md|html|php|yaml|json|twig|sh|bat)$ /error redirect;
}
location /vendor {
rewrite ^/vendor/(.*)\.(txt|md|html|php|yaml|json|twig|sh|bat)$ /error redirect;
}
# Remember to change 127.0.0.1:9000 to the Ip/port
# you configured php-cgi.exe to run from
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
}

View File

@@ -1,2 +1,11 @@
User-agent: * 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/

View File

@@ -1,110 +1,19 @@
body {
background-color: #eee;
}
body header { body header {
background: #349886; background: #8552A2;
border-left: 8px solid #29796B;
} }
body .clipboard { body .left-panel {
width: 28px; background: inherit;
height: 28px;
background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcAQMAAABIw03XAAAAA3NCSVQICAjb4U/gAAAABlBMVEX///////9VfPVsAAAAAnRSTlP/AOW3MEoAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAAFnRFWHRDcmVhdGlvbiBUaW1lADEwLzE1LzE0xr/LJAAAADhJREFUCJlj+P///wcGBPGDQR5E8OMi2IEEczOIaAQRHSCioQBGHAAR/7AT/z+DiA8MMALVXhABAJf9Sr5aY+UFAAAAAElFTkSuQmCC);
} }
body .exc-title-primary { body .exc-title-primary {
color: #1C3631; color: #fff;
text-shadow: none;
} }
body .exc-title { body .exc-title {
color: #2F5B52; color: #ddd;
text-shadow: none;
}
body .data-table-container label {
color: #0082BA;
}
body .frame {
border: 0;
}
body .frames-container {
overflow-y: auto;
overflow-x: hidden;
}
body .active .frame-class {
color: #E3D8E9;
}
body .frame-class {
color: #9055AF;
}
body .frame.active {
border: 0;
box-shadow: none;
background-color: #9055AF;
} }
body .frame:not(.active):hover { body .frame:not(.active):hover {
background: #e9e9e9; background: #e6e6e6;
}
body .frame-file, body .data-table tbody {
font-family: "DejaVu Sans Mono", Menlo, Monaco, Consolas, Courier, monospace;
font-size: 13px;
}
body .frame-code {
background: #305669;
border-left: 8px solid #253A47;
padding: 1rem;
}
body .frame-code .frame-file {
background: #253A47;
color: #eee;
text-shadow: none;
box-shadow: none;
font-family: inherit;
}
body .frame-code .frame-file strong {
color: #fff;
font-weight: normal;
}
body .frame-comments {
background: #283E4D;
box-shadow: none;
}
body .frame-comments.empty:before {
color: #789AAB;
}
body .details-container {
border: 0;
}
body .details {
background-color: #eee;
border-left: 8px solid #ddd;
padding: 1rem;
}
body .code-block {
background: #2C4454;
box-shadow: none;
font-family: "DejaVu Sans Mono", Menlo, Monaco, Consolas, Courier, monospace;
font-size: 13px;
}
body .handler.active {
background: #666;
} }

View File

@@ -20,6 +20,18 @@ form:
show_root: false show_root: false
help: PLUGIN_ADMIN.HOME_PAGE_HELP help: PLUGIN_ADMIN.HOME_PAGE_HELP
home.hide_in_urls:
type: toggle
label: PLUGIN_ADMIN.HIDE_HOME_IN_URLS
help: PLUGIN_ADMIN.HIDE_HOME_IN_URLS_HELP
highlight: 0
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
pages.theme: pages.theme:
type: themeselect type: themeselect
classes: fancy classes: fancy
@@ -73,7 +85,7 @@ form:
options: options:
"F jS \\a\\t g:ia": Date1 "F jS \\a\\t g:ia": Date1
"l jS \\of F g:i A": Date2 "l jS \\of F g:i A": Date2
"D, m M Y G:i:s": Date3 "D, d M Y G:i:s": Date3
"d-m-y G:i": Date4 "d-m-y G:i": Date4
"jS M Y": Date5 "jS M Y": Date5
@@ -86,7 +98,7 @@ form:
options: options:
"F jS \\a\\t g:ia": Date1 "F jS \\a\\t g:ia": Date1
"l jS \\of F g:i A": Date2 "l jS \\of F g:i A": Date2
"D, m M Y G:i:s": Date3 "D, d M Y G:i:s": Date3
"d-m-y G:i": Date4 "d-m-y G:i": Date4
"jS M Y": Date5 "jS M Y": Date5
@@ -142,6 +154,12 @@ form:
twig: Twig Events twig: Twig Events
use: keys use: keys
pages.append_url_extension:
type: text
placeholder: "e.g. .html"
label: PLUGIN_ADMIN.APPEND_URL_EXT
help: PLUGIN_ADMIN.APPEND_URL_EXT_HELP
pages.redirect_default_route: pages.redirect_default_route:
type: toggle type: toggle
label: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE label: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE
@@ -215,6 +233,19 @@ form:
validate: validate:
type: bool type: bool
pages.twig_first:
type: toggle
label: PLUGIN_ADMIN.TWIG_FIRST
highlight: asc
default: desc
help: PLUGIN_ADMIN.TWIG_FIRST_HELP
highlight: 0
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
languages: languages:
type: section type: section
title: PLUGIN_ADMIN.LANGUAGES title: PLUGIN_ADMIN.LANGUAGES
@@ -225,6 +256,7 @@ form:
languages.supported: languages.supported:
type: selectize type: selectize
size: large size: large
placeholder: "e.g. en, fr"
label: PLUGIN_ADMIN.SUPPORTED label: PLUGIN_ADMIN.SUPPORTED
help: PLUGIN_ADMIN.SUPPORTED_HELP help: PLUGIN_ADMIN.SUPPORTED_HELP
classes: fancy classes: fancy
@@ -509,6 +541,17 @@ form:
validate: validate:
type: bool 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: assets:
type: section type: section
title: PLUGIN_ADMIN.ASSETS title: PLUGIN_ADMIN.ASSETS
@@ -681,6 +724,17 @@ form:
validate: validate:
type: bool type: bool
images.cache_perms:
type: select
size: small
label: PLUGIN_ADMIN.CACHE_PERMS
help: PLUGIN_ADMIN.CACHE_PERMS_HELP
highlight: '0755'
options:
'0755': '0755'
'0775': '0775'
images.debug: images.debug:
type: toggle type: toggle
label: PLUGIN_ADMIN.IMAGES_DEBUG label: PLUGIN_ADMIN.IMAGES_DEBUG
@@ -711,6 +765,26 @@ form:
validate: validate:
type: bool type: bool
media.allowed_fallback_types:
type: selectize
size: large
label: PLUGIN_ADMIN.FALLBACK_TYPES
help: PLUGIN_ADMIN.FALLBACK_TYPES_HELP
classes: fancy
validate:
type: commalist
media.unsupported_inline_types:
type: selectize
size: large
label: PLUGIN_ADMIN.INLINE_TYPES
help: PLUGIN_ADMIN.INLINE_TYPES_HELP
classes: fancy
validate:
type: commalist
session: session:
type: section type: section
title: PLUGIN_ADMIN.SESSION title: PLUGIN_ADMIN.SESSION
@@ -718,13 +792,14 @@ form:
fields: fields:
session.enabled: session.enabled:
type: toggle type: hidden
label: PLUGIN_ADMIN.ENABLED label: PLUGIN_ADMIN.ENABLED
help: PLUGIN_ADMIN.SESSION_ENABLED_HELP help: PLUGIN_ADMIN.SESSION_ENABLED_HELP
highlight: 1 highlight: 1
options: options:
1: PLUGIN_ADMIN.YES 1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO 0: PLUGIN_ADMIN.NO
default: true
validate: validate:
type: bool type: bool
@@ -743,6 +818,29 @@ form:
label: PLUGIN_ADMIN.NAME label: PLUGIN_ADMIN.NAME
help: PLUGIN_ADMIN.SESSION_NAME_HELP help: PLUGIN_ADMIN.SESSION_NAME_HELP
session.secure:
type: toggle
label: PLUGIN_ADMIN.SESSION_SECURE
help: PLUGIN_ADMIN.SESSION_SECURE_HELP
highlight: 1
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
default: false
validate:
type: bool
session.httponly:
type: toggle
label: PLUGIN_ADMIN.SESSION_HTTPONLY
help: PLUGIN_ADMIN.SESSION_HTTPONLY_HELP
highlight: 1
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
default: true
validate:
type: bool
advanced: advanced:
type: section type: section
@@ -750,6 +848,17 @@ form:
underline: true underline: true
fields: fields:
wrapped_site:
type: toggle
label: PLUGIN_ADMIN.WRAPPED_SITE
highlight: 0
help: PLUGIN_ADMIN.WRAPPED_SITE_HELP
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
absolute_urls: absolute_urls:
type: toggle type: toggle
label: PLUGIN_ADMIN.ABSOLUTE_URLS label: PLUGIN_ADMIN.ABSOLUTE_URLS
@@ -763,6 +872,7 @@ form:
param_sep: param_sep:
type: select type: select
size: medium
label: PLUGIN_ADMIN.PARAMETER_SEPARATOR label: PLUGIN_ADMIN.PARAMETER_SEPARATOR
classes: fancy classes: fancy
help: PLUGIN_ADMIN.PARAMETER_SEPARATOR_HELP help: PLUGIN_ADMIN.PARAMETER_SEPARATOR_HELP

View File

@@ -0,0 +1,7 @@
form:
validation: loose
fields:
alt_text:
type: string
label: Alt Text

View 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'

View File

@@ -0,0 +1,8 @@
form:
validation: loose
fields:
new_file_name:
type: text
label: PLUGIN_ADMIN_PRO.NEW_FILE_NAME
validate:
required: true

View File

@@ -29,7 +29,7 @@ form:
content: content:
type: markdown type: markdown
label: PLUGIN_ADMIN.CONTENT showPreview: true
validate: validate:
type: textarea type: textarea
@@ -88,7 +88,6 @@ form:
placeholder_key: PLUGIN_ADMIN.METADATA_KEY placeholder_key: PLUGIN_ADMIN.METADATA_KEY
placeholder_value: PLUGIN_ADMIN.METADATA_VALUE placeholder_value: PLUGIN_ADMIN.METADATA_VALUE
taxonomies: taxonomies:
type: section type: section
title: PLUGIN_ADMIN.TAXONOMIES title: PLUGIN_ADMIN.TAXONOMIES
@@ -264,6 +263,12 @@ form:
default: default default: default
'@data-options': '\Grav\Common\Page\Pages::types' '@data-options': '\Grav\Common\Page\Pages::types'
header.append_url_extension:
type: text
label: PLUGIN_ADMIN.APPEND_URL_EXT
toggleable: true
help: PLUGIN_ADMIN.APPEND_URL_EXT_HELP
header.order_by: header.order_by:
type: hidden type: hidden

View File

@@ -25,7 +25,7 @@ form:
content: content:
type: markdown type: markdown
label: PLUGIN_ADMIN.CONTENT showPreview: true
uploads: uploads:
type: pagemedia type: pagemedia

View File

@@ -25,7 +25,7 @@ form:
content: content:
type: markdown type: markdown
label: PLUGIN_ADMIN.CONTENT showPreview: true
uploads: uploads:
type: pagemedia type: pagemedia

View File

@@ -29,7 +29,7 @@ form:
size: large size: large
label: PLUGIN_ADMIN.PASSWORD label: PLUGIN_ADMIN.PASSWORD
validate: validate:
required: true required: false
message: PLUGIN_ADMIN.PASSWORD_VALIDATION_MESSAGE message: PLUGIN_ADMIN.PASSWORD_VALIDATION_MESSAGE
pattern: '(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}' pattern: '(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}'
@@ -54,3 +54,32 @@ form:
default: 'en' default: 'en'
help: PLUGIN_ADMIN.LANGUAGE_HELP help: PLUGIN_ADMIN.LANGUAGE_HELP
security:
title: PLUGIN_ADMIN.ACCESS_LEVELS
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

View 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

View 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

View File

@@ -168,6 +168,10 @@ zip:
type: file type: file
thumb: media/thumb-zip.png thumb: media/thumb-zip.png
mime: application/zip mime: application/zip
7z:
type: file
thumb: media/thumb-7zip.png
mime: application/x-7z-compressed
gz: gz:
type: file type: file
thumb: media/thumb-gz.png thumb: media/thumb-gz.png

View File

@@ -1,9 +1,4 @@
schemes: schemes:
asset:
type: ReadOnlyStream
paths:
- assets
image: image:
type: ReadOnlyStream type: ReadOnlyStream
paths: paths:

View File

@@ -1,110 +1,116 @@
absolute_urls: false # Absolute or relative URLs for `base_url` absolute_urls: false # Absolute or relative URLs for `base_url`
timezone: '' # Valid values: http://php.net/manual/en/timezones.php timezone: '' # Valid values: http://php.net/manual/en/timezones.php
default_locale: # Default locale (defaults to system) default_locale: # Default locale (defaults to system)
param_sep: ':' # Parameter separator, use ';' for Apache on windows param_sep: ':' # Parameter separator, use ';' for Apache on windows
wrapped_site: false # For themes/plugins to know if Grav is wrapped by another platform
languages: languages:
supported: [] # List of languages supported. eg: [en, fr, de] supported: [] # List of languages supported. eg: [en, fr, de]
include_default_lang: true # Include the default lang prefix in all URLs include_default_lang: true # Include the default lang prefix in all URLs
translations: true # Enable translations by default translations: true # Enable translations by default
translations_fallback: true # Fallback through supported translations if active lang doesn't exist translations_fallback: true # Fallback through supported translations if active lang doesn't exist
session_store_active: false # Store active language in session session_store_active: false # Store active language in session
http_accept_language: false # Attempt to set the language based on http_accept_language header in the browser http_accept_language: false # Attempt to set the language based on http_accept_language header in the browser
override_locale: false # Override the default or system locale with language specific one override_locale: false # Override the default or system locale with language specific one
home: home:
alias: '/home' # Default path for home, ie / alias: '/home' # Default path for home, ie /
hide_in_urls: false # Hide the home route in URLs
pages: pages:
theme: antimatter # Default theme (defaults to "antimatter" theme) theme: antimatter # Default theme (defaults to "antimatter" theme)
order: order:
by: default # Order pages by "default", "alpha" or "date" by: default # Order pages by "default", "alpha" or "date"
dir: asc # Default ordering direction, "asc" or "desc" dir: asc # Default ordering direction, "asc" or "desc"
list: list:
count: 20 # Default item count per page count: 20 # Default item count per page
dateformat: dateformat:
default: # The default date format Grav expects in the `date: ` field default: # The default date format Grav expects in the `date: ` field
short: 'jS M Y' # Short date format short: 'jS M Y' # Short date format
long: 'F jS \a\t g:ia' # Long date format long: 'F jS \a\t g:ia' # Long date format
publish_dates: true # automatically publish/unpublish based on dates publish_dates: true # automatically publish/unpublish based on dates
process: process:
markdown: true # Process Markdown markdown: true # Process Markdown
twig: false # Process Twig twig: false # Process Twig
twig_first: false # Process Twig before markdown when processing both on a page
events: events:
page: true # Enable page level events page: true # Enable page level events
twig: true # Enable twig level events twig: true # Enable twig level events
markdown: markdown:
extra: false # Enable support for Markdown Extra support (GFM by default) extra: false # Enable support for Markdown Extra support (GFM by default)
auto_line_breaks: false # Enable automatic line breaks auto_line_breaks: false # Enable automatic line breaks
auto_url_links: false # Enable automatic HTML links auto_url_links: false # Enable automatic HTML links
escape_markup: false # Escape markup tags into entities escape_markup: false # Escape markup tags into entities
special_chars: # List of special characters to automatically convert to entities special_chars: # List of special characters to automatically convert to entities
'>': 'gt' '>': 'gt'
'<': 'lt' '<': 'lt'
types: [txt,xml,html,json,rss,atom] # list of valid page types types: [txt,xml,html,htm,json,rss,atom] # list of valid page types
expires: 604800 # Page expires time in seconds (604800 seconds = 7 days) append_url_extension: '' # Append page's extension in Page urls (e.g. '.html' results in /path/page.html)
last_modified: false # Set the last modified date header based on file modifcation timestamp expires: 604800 # Page expires time in seconds (604800 seconds = 7 days)
etag: false # Set the etag header tag last_modified: false # Set the last modified date header based on file modifcation timestamp
vary_accept_encoding: false # Add `Vary: Accept-Encoding` header etag: false # Set the etag header tag
redirect_default_route: false # Automatically redirect to a page's default route vary_accept_encoding: false # Add `Vary: Accept-Encoding` header
redirect_default_code: 301 # Default code to use for redirects redirect_default_route: false # Automatically redirect to a page's default route
redirect_trailing_slash: true # Handle automatically or 301 redirect a trailing / URL redirect_default_code: 301 # Default code to use for redirects
ignore_files: [.DS_Store] # Files to ignore in Pages redirect_trailing_slash: true # Handle automatically or 301 redirect a trailing / URL
ignore_folders: [.git, .idea] # Folders to ignore in Pages ignore_files: [.DS_Store] # Files to ignore in Pages
ignore_hidden: true # Ignore all Hidden files and folders ignore_folders: [.git, .idea] # Folders to ignore in Pages
url_taxonomy_filters: true # Enable auto-magic URL-based taxonomy filters for page collections ignore_hidden: true # Ignore all Hidden files and folders
url_taxonomy_filters: true # Enable auto-magic URL-based taxonomy filters for page collections
cache: cache:
enabled: true # Set to true to enable caching enabled: true # Set to true to enable caching
check: check:
method: file # Method to check for updates in pages: file|folder|none method: file # Method to check for updates in pages: file|folder|none
driver: auto # One of: auto|file|apc|xcache|memcache|wincache driver: auto # One of: auto|file|apc|xcache|memcache|wincache
prefix: 'g' # Cache prefix string (prevents cache conflicts) prefix: 'g' # Cache prefix string (prevents cache conflicts)
lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite) lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite)
gzip: false # GZip compress the page output gzip: false # GZip compress the page output
twig: twig:
cache: true # Set to true to enable twig caching cache: true # Set to true to enable twig caching
debug: false # Enable Twig debug debug: false # Enable Twig debug
auto_reload: true # Refresh cache on changes auto_reload: true # Refresh cache on changes
autoescape: false # Autoescape Twig vars autoescape: false # Autoescape Twig vars
undefined_functions: true # Allow undefined functions undefined_functions: true # Allow undefined functions
undefined_filters: true # Allow undefined filters undefined_filters: true # Allow undefined filters
umask_fix: false # By default Twig creates cached files as 755, fix switches this to 775
assets: # Configuration for Assets Manager (JS, CSS) assets: # Configuration for Assets Manager (JS, CSS)
css_pipeline: false # The CSS pipeline is the unification of multiple CSS resources into one file css_pipeline: false # The CSS pipeline is the unification of multiple CSS resources into one file
css_minify: true # Minify the CSS during pipelining css_minify: true # Minify the CSS during pipelining
css_minify_windows: false # Minify Override for Windows platforms. False by default due to ThreadStackSize css_minify_windows: false # Minify Override for Windows platforms. False by default due to ThreadStackSize
css_rewrite: true # Rewrite any CSS relative URLs during pipelining css_rewrite: true # Rewrite any CSS relative URLs during pipelining
js_pipeline: false # The JS pipeline is the unification of multiple JS resources into one file js_pipeline: false # The JS pipeline is the unification of multiple JS resources into one file
js_minify: true # Minify the JS during pipelining js_minify: true # Minify the JS during pipelining
enable_asset_timestamp: false # Enable asset timestamps enable_asset_timestamp: false # Enable asset timestamps
collections: collections:
jquery: system://assets/jquery/jquery-2.1.4.min.js jquery: system://assets/jquery/jquery-2.1.4.min.js
errors: errors:
display: false # Display full backtrace-style error page display: false # Display full backtrace-style error page
log: true # Log errors to /logs folder log: true # Log errors to /logs folder
debugger: debugger:
enabled: false # Enable Grav debugger and following settings enabled: false # Enable Grav debugger and following settings
shutdown: shutdown:
close_connection: true # Close the connection before calling onShutdown(). false for debugging close_connection: true # Close the connection before calling onShutdown(). false for debugging
images: images:
default_image_quality: 85 # Default image quality to use when resampling images (85%) default_image_quality: 85 # Default image quality to use when resampling images (85%)
cache_all: false # Cache all image by default cache_all: false # Cache all image by default
debug: false # Show an overlay over images indicating the pixel depth of the image when working with retina for example cache_perms: '0755' # MUST BE IN QUOTES!! Default cache folder perms. Usually '0755' or '0775'
debug: false # Show an overlay over images indicating the pixel depth of the image when working with retina for example
media: media:
enable_media_timestamp: false # Enable media timetsamps enable_media_timestamp: false # Enable media timetsamps
upload_limit: 0 # Set maximum upload size in bytes (0 is unlimited) upload_limit: 0 # Set maximum upload size in bytes (0 is unlimited)
unsupported_inline_types: [] # Array of unsupported media file types to try to display inline unsupported_inline_types: [] # Array of supported media types to try to display inline
allowed_fallback_types: [] # Array of allowed media types of files found if accessed via Page route
session: session:
enabled: true # Enable Session support enabled: true # Enable Session support
timeout: 1800 # Timeout in seconds 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
secure: false # Set session secure. If true, indicates that communication for this cookie must be over an encrypted transmission. Enable this only on sites that run exclusively on HTTPS
security: httponly: true # Set session HTTP only. If true, indicates that cookies should be used only over HTTP, and JavaScript modification is not allowed.
default_hash: $2y$10$kwsyMVwM8/7j0K/6LHT.g.Fs49xOCTp2b8hh/S5.dPJuJcJB6T.UK

View File

@@ -2,8 +2,9 @@
// Some standard defines // Some standard defines
define('GRAV', true); define('GRAV', true);
define('GRAV_VERSION', '1.0.0-rc.1'); define('GRAV_VERSION', '1.0.8');
define('DS', '/'); define('DS', '/');
define('GRAV_PHP_MIN', '5.5.9');
// Directories and Paths // Directories and Paths
if (!defined('GRAV_ROOT')) { if (!defined('GRAV_ROOT')) {
@@ -13,14 +14,14 @@ define('ROOT_DIR', GRAV_ROOT . '/');
define('USER_PATH', 'user/'); define('USER_PATH', 'user/');
define('USER_DIR', ROOT_DIR . USER_PATH); define('USER_DIR', ROOT_DIR . USER_PATH);
define('SYSTEM_DIR', ROOT_DIR .'system/'); define('SYSTEM_DIR', ROOT_DIR .'system/');
define('ASSETS_DIR', ROOT_DIR . 'assets/');
define('CACHE_DIR', ROOT_DIR . 'cache/'); define('CACHE_DIR', ROOT_DIR . 'cache/');
define('IMAGES_DIR', ROOT_DIR . 'images/');
define('LOG_DIR', ROOT_DIR .'logs/'); define('LOG_DIR', ROOT_DIR .'logs/');
define('ACCOUNTS_DIR', USER_DIR .'accounts/');
define('PAGES_DIR', USER_DIR .'pages/');
// DEPRECATED: Do not use! // DEPRECATED: Do not use!
define('ASSETS_DIR', ROOT_DIR . 'assets/');
define('IMAGES_DIR', ROOT_DIR . 'images/');
define('ACCOUNTS_DIR', USER_DIR .'accounts/');
define('PAGES_DIR', USER_DIR .'pages/');
define('DATA_DIR', USER_DIR .'data/'); define('DATA_DIR', USER_DIR .'data/');
define('LIB_DIR', SYSTEM_DIR .'src/'); define('LIB_DIR', SYSTEM_DIR .'src/');
define('PLUGINS_DIR', USER_DIR .'plugins/'); define('PLUGINS_DIR', USER_DIR .'plugins/');

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

View File

@@ -35,3 +35,5 @@ NICETIME:
MO_PLURAL: m MO_PLURAL: m
YR_PLURAL: r YR_PLURAL: r
DEC_PLURAL: dek DEC_PLURAL: dek
MONTHS_OF_THE_YEAR: ['Leden', 'Únor', 'Březen', 'Duben', 'Květen', 'Červen', 'Červenec', 'Srpen', 'Září', 'Říjen', 'Listopad', 'Prosinec']
DAYS_OF_THE_WEEK: ['Pondělí', 'Úterý', 'Středa', 'Čtvrtek', 'Pátek', 'Sobota', 'Neděle']

View File

@@ -1,43 +1,45 @@
INFLECTOR_IRREGULAR: INFLECTOR_IRREGULAR:
'person': 'personen' 'person': 'Personen'
'man': 'menschen' 'man': 'Menschen'
'child': 'kinder' 'child': 'Kinder'
'sex': 'geschlecht' 'sex': 'Geschlecht'
'move': 'züge' 'move': 'Züge'
NICETIME: NICETIME:
NO_DATE_PROVIDED: Keine Daten vorhanden NO_DATE_PROVIDED: Keine Daten vorhanden
BAD_DATE: Falsches Datum BAD_DATE: Falsches Datum
AGO: her AGO: her
FROM_NOW: ab jetzt FROM_NOW: ab jetzt
SECOND: sekunde SECOND: Sekunde
MINUTE: minute MINUTE: Minute
HOUR: stunde HOUR: Stunde
DAY: tag DAY: Tag
WEEK: woche WEEK: Woche
MONTH: monat MONTH: Monat
YEAR: jahr YEAR: Jahr
DECADE: dekade DECADE: Dekade
SEC: sek SEC: sek
MIN: min MIN: min
HR: std HR: std
DAY: tag DAY: Tag
WK: wo WK: wo
MO: mo MO: mo
YR: yh YR: yh
DEC: dec DEC: dec
SECOND_PLURAL: sekunden SECOND_PLURAL: Sekunden
MINUTE_PLURAL: minuten MINUTE_PLURAL: Minuten
HOUR_PLURAL: stunden HOUR_PLURAL: Stunden
DAY_PLURAL: tage DAY_PLURAL: Tage
WEEK_PLURAL: wochen WEEK_PLURAL: Wochen
MONTH_PLURAL: monate MONTH_PLURAL: Monate
YEAR_PLURAL: jahre YEAR_PLURAL: Jahre
DECADE_PLURAL: dekaden DECADE_PLURAL: Dekaden
SEC_PLURAL: sekunden SEC_PLURAL: Sekunden
MIN_PLURAL: minuten MIN_PLURAL: Minuten
HR_PLURAL: stunden HR_PLURAL: Stunden
DAY_PLURAL: tage DAY_PLURAL: Tage
WK_PLURAL: wochen WK_PLURAL: Wochen
MO_PLURAL: monate MO_PLURAL: Monate
YR_PLURAL: jahre YR_PLURAL: Jahre
DEC_PLURAL: dekaden DEC_PLURAL: Dekaden
MONTHS_OF_THE_YEAR: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember']
DAYS_OF_THE_WEEK: ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag']

2
system/languages/el.yaml Normal file
View File

@@ -0,0 +1,2 @@
MONTHS_OF_THE_YEAR: ['Ιανουάριος', 'Φεβρουάριος', 'Μάρτιος', 'Απρίλιος', 'Μάιος', 'Ιούνιος', 'Ιούλιος', 'Αύγουστος', 'Σεπτέμβριος', 'Οκτώβριος', 'Νοέμβριος', 'Δεκέμβριος']
DAYS_OF_THE_WEEK: ['Δευτέρα', 'Τρλιτη', 'Τετάρτη', 'Πέμπτη', 'Παρασκευή', 'Σαββάτο', 'Κυριακή']

View File

@@ -92,3 +92,9 @@ NICETIME:
MO_PLURAL: mos MO_PLURAL: mos
YR_PLURAL: yrs YR_PLURAL: yrs
DEC_PLURAL: decs DEC_PLURAL: decs
FORM:
VALIDATION_FAIL: <b>Validation failed:</b>
INVALID_INPUT: Invalid input in
MISSING_REQUIRED_FIELD: Missing required field:
MONTHS_OF_THE_YEAR: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
DAYS_OF_THE_WEEK: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']

44
system/languages/es.yaml Normal file
View File

@@ -0,0 +1,44 @@
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: "
MONTHS_OF_THE_YEAR: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Augosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre']
DAYS_OF_THE_WEEK: ['Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo']

2
system/languages/fi.yaml Normal file
View File

@@ -0,0 +1,2 @@
MONTHSOFTHE_YEAR: ['Tammikuu', 'Helmikuu', 'Maaliskuu', 'Huhtikuu', 'Toukokuu', 'Kesäkuu', 'Heinäkuu', 'Elokuu', 'Syyskuu', 'Lokakuu', 'Marraskuu', 'Joulukuu']
DAYSOFTHE_WEEK: ['Maanantai', 'Tiistai', 'Keskiviikko', 'Torstai', 'Perjantai', 'Lauantai', 'Sunnuntai']

View File

@@ -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: INFLECTOR_PLURALS:
'/$/': 's' '/(quiz)$/i': '\1zes'
'/(bijou|caillou|chou|genou|hibou|joujou|pou|au|eu|eau)$/': '\1x' '/^(ox)$/i': '\1en'
'/(bleu|émeu|landau|lieu|pneu|sarrau)$/': '\1s' '/([m|l])ouse$/i': '\1ice'
'/(b|cor|ém|gemm|soupir|trav|vant|vitr)ail$/': '\1aux' '/(matr|vert|ind)ix|ex$/i': '\1ices'
'/(s|x|z)$/': '\1' '/(x|ch|ss|sh)$/i': '\1es'
'/ail$/': 'ails' '/([^aeiouy]|qu)ies$/i': '\1y'
'/al$/': 'aux' '/([^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$/i': 's'
'/$/': 's'
INFLECTOR_SINGULAR: INFLECTOR_SINGULAR:
'/(bijou|caillou|chou|genou|hibou|joujou|pou|au|eu|eau)x$/': '\1' '/(quiz)zes$/i': '\1'
'/(b|cor|ém|gemm|soupir|trav|vant|vitr)aux$/': '\1ail' '/(matr)ices$/i': '\1ix'
'/(journ|chev)aux$/': '\1al' '/(vert|ind)ices$/i': '\1ex'
'/ails$/': 'ail' '/^(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': '' '/s$/i': ''
INFLECTOR_UNCOUNTABLE: ['équipement', 'information', 'riz', 'argent', 'espèces', 'séries', 'poisson', 'mouton']
INFLECTOR_IRREGULAR: INFLECTOR_IRREGULAR:
'madame': 'mesdames' 'person': 'personnes'
'mademoiselle': 'mesdemoiselles' 'man': 'hommes'
'monsieur': 'messieurs' 'child': 'enfants'
'sex': 'sexes'
'move': 'déplacements'
INFLECTOR_ORDINALS: INFLECTOR_ORDINALS:
'default': 'ème' 'default': 'ème'
'first': 'er' 'first': 'er'
'second': 'nd' 'second': 'nd'
'third': 'ème'
NICETIME: NICETIME:
NO_DATE_PROVIDED: Aucune date NO_DATE_PROVIDED: Aucune date
BAD_DATE: Date erronée BAD_DATE: Date erronée
@@ -48,7 +82,7 @@ NICETIME:
DAY_PLURAL: jours DAY_PLURAL: jours
WEEK_PLURAL: semaines WEEK_PLURAL: semaines
MONTH_PLURAL: mois MONTH_PLURAL: mois
YEAR_PLURAL: ans YEAR_PLURAL: années
DECADE_PLURAL: décennies DECADE_PLURAL: décennies
SEC_PLURAL: s SEC_PLURAL: s
MIN_PLURAL: m MIN_PLURAL: m
@@ -58,3 +92,9 @@ NICETIME:
MO_PLURAL: m MO_PLURAL: m
YR_PLURAL: a YR_PLURAL: a
DEC_PLURAL: d DEC_PLURAL: d
FORM:
VALIDATION_FAIL: <b>La validation a échoué :</b>
INVALID_INPUT: Saisie non valide
MISSING_REQUIRED_FIELD: Champ obligatoire manquant :
MONTHS_OF_THE_YEAR: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']
DAYS_OF_THE_WEEK: ['Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche']

52
system/languages/hr.yaml Normal file
View File

@@ -0,0 +1,52 @@
INFLECTOR_IRREGULAR:
'person': 'Osoba'
'man': 'Čovjek'
'child': 'Dijete'
'sex': 'Spol'
'move': 'Pomakni'
NICETIME:
NO_DATE_PROVIDED: Datum nije upisan
BAD_DATE: Pogrešan datum
AGO: prije
FROM_NOW: od sad
SECOND: sekundi
MINUTE: minuta
HOUR: godina
DAY: dan
WEEK: tjedan
MONTH: mjesec
YEAR: godina
DECADE: desetljeće
SEC: sek
MIN: min
HR: sat
DAY: dan
WK: t
MO: m
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
HR_PLURAL: sat
DAY_PLURAL: dan
WK_PLURAL: t
MO_PLURAL: m
YR_PLURAL: g
DEC_PLURAL: des
FORM:
VALIDATION_FAIL: <b>Validacija nije uspjela:</b>
INVALID_INPUT: Unos nije valjan

53
system/languages/hu.yaml Normal file
View 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:
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:
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:

View File

@@ -19,3 +19,9 @@ NICETIME:
MONTH_PLURAL: mesi MONTH_PLURAL: mesi
YEAR_PLURAL: anni YEAR_PLURAL: anni
DECADE_PLURAL: decadi DECADE_PLURAL: decadi
FORM:
VALIDATION_FAIL: <b>Validazione fallita:</b>
INVALID_INPUT: Input invalido in
MISSING_REQUIRED_FIELD: Campo richiesto mancante:
MONTHS_OF_THE_YEAR: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre']
DAYS_OF_THE_WEEK: ['Lunedi', 'Martedi', 'Mercoledi', 'Giovedi', 'Venerdi', 'Sabato', 'Domenica']

2
system/languages/nb.yaml Normal file
View File

@@ -0,0 +1,2 @@
MONTHS_OF_THE_YEAR: ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember']
DAYS_OF_THE_WEEK: ['mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag']

View File

@@ -41,3 +41,5 @@ NICETIME:
MO_PLURAL: maanden MO_PLURAL: maanden
YR_PLURAL: jaren YR_PLURAL: jaren
DEC_PLURAL: decs DEC_PLURAL: decs
MONTHS_OF_THE_YEAR: ['Januari', 'Februari', 'Maart', 'April', 'Mei', 'Juni', 'Juli', 'Augustus', 'September', 'Oktober', 'November', 'December']
DAYS_OF_THE_WEEK: ['Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrijdag', 'Zaterdag', 'Zondag']

2
system/languages/pl.yaml Normal file
View File

@@ -0,0 +1,2 @@
MONTHS_OF_THE_YEAR: ['Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec', 'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień']
DAYS_OF_THE_WEEK: ['Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota', 'Niedziela']

2
system/languages/pt.yaml Normal file
View File

@@ -0,0 +1,2 @@
MONTHS_OF_THE_YEAR: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro']
DAYS_OF_THE_WEEK: ['Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado', 'Domingo']

2
system/languages/ro.yaml Normal file
View File

@@ -0,0 +1,2 @@
MONTHS_OF_THE_YEAR: ['Ianuarie', 'Februarie', 'Martie', 'Aprilue', 'Mai', 'Iunie', 'Iulie', 'August', 'Septembrie', 'Octombrie', 'Noiembrie', 'Decembrie']
DAYS_OF_THE_WEEK: ['Luni', 'Marti', 'Miercuri', 'Joi', 'Vineri', 'Sâmbătă', 'Duminică']

View File

@@ -41,3 +41,5 @@ NICETIME:
MO_PLURAL: мес MO_PLURAL: мес
YR_PLURAL: г. YR_PLURAL: г.
DEC_PLURAL: гг. DEC_PLURAL: гг.
MONTHS_OF_THE_YEAR: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь']
DAYS_OF_THE_WEEK: ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье']

37
system/languages/tr.yaml Normal file
View File

@@ -0,0 +1,37 @@
NICETIME:
NO_DATE_PROVIDED: Tarih yok
BAD_DATE: Yanlış tarih
AGO: önce
FROM_NOW: (şimdiden)
SECOND: saniye
MINUTE: dakika
HOUR: saat
DAY: gün
WEEK: hafta
MONTH: ay
YEAR: yıl
DECADE: onyıl
SEC: sn
MIN: dk
HR: sa
DAY: gün
WK: hft
MO: ay
YR: yl
DEC: onyl
SECOND_PLURAL: saniye
MINUTE_PLURAL: dakika
HOUR_PLURAL: saat
DAY_PLURAL: gün
WEEK_PLURAL: hafta
MONTH_PLURAL: ay
YEAR_PLURAL: yıl
DECADE_PLURAL: onyıl
SEC_PLURAL: sn
MIN_PLURAL: dk
HR_PLURAL: sa
DAY_PLURAL: gün
WK_PLURAL: hft
MO_PLURAL: ay
YR_PLURAL: yl
DEC_PLURAL: onyl

View File

@@ -42,6 +42,8 @@ class Assets
/** @const Regex to match CSS import content */ /** @const Regex to match CSS import content */
const CSS_IMPORT_REGEX = '{@import(.*);}'; const CSS_IMPORT_REGEX = '{@import(.*);}';
const HTML_TAG_REGEX = '#(<([A-Z][A-Z0-9]*)>)+(.*)(<\/\2>)#is';
/** /**
* Closure used by the pipeline to fetch assets. * Closure used by the pipeline to fetch assets.
@@ -72,6 +74,8 @@ class Assets
protected $config; protected $config;
protected $base_url; protected $base_url;
protected $timestamp = ''; protected $timestamp = '';
protected $assets_dir;
protected $assets_url;
// Default values for pipeline settings // Default values for pipeline settings
protected $css_minify = true; protected $css_minify = true;
@@ -115,7 +119,7 @@ class Assets
} }
// Pipeline requires public dir // Pipeline requires public dir
if (($this->js_pipeline || $this->css_pipeline) && !is_dir(ASSETS_DIR)) { if (($this->js_pipeline || $this->css_pipeline) && !is_dir($this->assets_dir)) {
throw new \Exception('Assets: Public dir not found'); throw new \Exception('Assets: Public dir not found');
} }
@@ -173,11 +177,16 @@ class Assets
$base_url = self::getGrav()['base_url']; $base_url = self::getGrav()['base_url'];
$asset_config = (array)$config->get('system.assets'); $asset_config = (array)$config->get('system.assets');
/** @var Locator $locator */
$locator = self::$grav['locator'];
$this->assets_dir = self::getGrav()['locator']->findResource('asset://') . DS;
$this->assets_url = self::getGrav()['locator']->findResource('asset://', false);
$this->config($asset_config); $this->config($asset_config);
$this->base_url = $base_url . '/'; $this->base_url = $base_url . '/';
// Register any preconfigured collections // Register any preconfigured collections
foreach ($config->get('system.assets.collections') as $name => $collection) { foreach ($config->get('system.assets.collections', []) as $name => $collection) {
$this->registerCollection($name, (array)$collection); $this->registerCollection($name, (array)$collection);
} }
} }
@@ -194,7 +203,7 @@ class Assets
* *
* @return $this * @return $this
*/ */
public function add($asset, $priority = null, $pipeline = null) public function add($asset, $priority = null, $pipeline = true)
{ {
// More than one asset // More than one asset
if (is_array($asset)) { if (is_array($asset)) {
@@ -227,21 +236,22 @@ class Assets
* It checks for duplicates. * It checks for duplicates.
* You may add more than one asset passing an array as argument. * You may add more than one asset passing an array as argument.
* *
* @param mixed $asset * @param mixed $asset
* @param int $priority the priority, bigger comes first * @param int $priority the priority, bigger comes first
* @param bool $pipeline false if this should not be pipelined * @param bool $pipeline false if this should not be pipelined
* @param null $group
* *
* @return $this * @return $this
*/ */
public function addCss($asset, $priority = null, $pipeline = null) public function addCss($asset, $priority = null, $pipeline = true, $group = null)
{ {
if (is_array($asset)) { if (is_array($asset)) {
foreach ($asset as $a) { foreach ($asset as $a) {
$this->addCss($a, $priority, $pipeline); $this->addCss($a, $priority, $pipeline, $group);
} }
return $this; return $this;
} elseif (isset($this->collections[$asset])) { } elseif (isset($this->collections[$asset])) {
$this->add($this->collections[$asset], $priority, $pipeline); $this->add($this->collections[$asset], $priority, $pipeline, $group);
return $this; return $this;
} }
@@ -249,15 +259,20 @@ class Assets
$asset = $this->buildLocalLink($asset); $asset = $this->buildLocalLink($asset);
} }
// Check for existence
if ($asset === false) {
return $this;
}
$data = [ $data = [
'asset' => $asset, 'asset' => $asset,
'priority' => intval($priority ?: 10), 'priority' => intval($priority ?: 10),
'order' => count($this->css), 'order' => count($this->css),
'pipeline' => $pipeline ?: true 'pipeline' => (bool) $pipeline,
'group' => $group ?: 'head'
]; ];
// check for dynamic array and merge with defaults // check for dynamic array and merge with defaults
$count_args = func_num_args();
if (func_num_args() == 2) { if (func_num_args() == 2) {
$dynamic_arg = func_get_arg(1); $dynamic_arg = func_get_arg(1);
if (is_array($dynamic_arg)) { if (is_array($dynamic_arg)) {
@@ -286,7 +301,7 @@ class Assets
* @param string $group name of the group * @param string $group name of the group
* @return $this * @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)) { if (is_array($asset)) {
foreach ($asset as $a) { foreach ($asset as $a) {
@@ -302,17 +317,21 @@ class Assets
$asset = $this->buildLocalLink($asset); $asset = $this->buildLocalLink($asset);
} }
// Check for existence
if ($asset === false) {
return $this;
}
$data = [ $data = [
'asset' => $asset, 'asset' => $asset,
'priority' => intval($priority ?: 10), 'priority' => intval($priority ?: 10),
'order' => count($this->js), 'order' => count($this->js),
'pipeline' => $pipeline ?: true, 'pipeline' => (bool) $pipeline,
'loading' => $loading ?: '', 'loading' => $loading ?: '',
'group' => $group ?: 'head' 'group' => $group ?: 'head'
]; ];
// check for dynamic array and merge with defaults // check for dynamic array and merge with defaults
$count_args = func_num_args();
if (func_num_args() == 2) { if (func_num_args() == 2) {
$dynamic_arg = func_get_arg(1); $dynamic_arg = func_get_arg(1);
if (is_array($dynamic_arg)) { if (is_array($dynamic_arg)) {
@@ -340,7 +359,7 @@ class Assets
* *
* @return \Grav\Common\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); return $this->addJs($asset, $priority, $pipeline, 'async', $group);
} }
@@ -357,7 +376,7 @@ class Assets
* *
* @return \Grav\Common\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); return $this->addJs($asset, $priority, $pipeline, 'defer', $group);
} }
@@ -369,20 +388,27 @@ class Assets
* For adding chunks of string-based inline CSS * For adding chunks of string-based inline CSS
* *
* @param mixed $asset * @param mixed $asset
* @param int $priority the priority, bigger comes first * @param int $priority the priority, bigger comes first
* @param null $group
* *
* @return $this * @return $this
*/ */
public function addInlineCss($asset, $priority = null) public function addInlineCss($asset, $priority = null, $group = null)
{ {
$asset = trim($asset);
if (is_a($asset, 'Twig_Markup')) { if (is_a($asset, 'Twig_Markup')) {
$asset = strip_tags((string)$asset); preg_match(self::HTML_TAG_REGEX, $asset, $matches );
if (isset($matches[3])) {
$asset = $matches[3];
}
} }
$data = [ $data = [
'priority' => intval($priority ?: 10), 'priority' => intval($priority ?: 10),
'order' => count($this->inline_css), 'order' => count($this->inline_css),
'asset' => $asset 'asset' => $asset,
'group' => $group ?: 'head'
]; ];
// check for dynamic array and merge with defaults // check for dynamic array and merge with defaults
@@ -395,7 +421,7 @@ class Assets
} }
$key = md5($asset); $key = md5($asset);
if (is_string($asset) && !array_key_exists($key, $this->inline_css)) { if ($asset && is_string($asset) && !array_key_exists($key, $this->inline_css)) {
$this->inline_css[$key] = $data; $this->inline_css[$key] = $data;
} }
@@ -416,8 +442,13 @@ class Assets
*/ */
public function addInlineJs($asset, $priority = null, $group = null) public function addInlineJs($asset, $priority = null, $group = null)
{ {
$asset = trim($asset);
if (is_a($asset, 'Twig_Markup')) { if (is_a($asset, 'Twig_Markup')) {
$asset = strip_tags((string)$asset); preg_match(self::HTML_TAG_REGEX, $asset, $matches );
if (isset($matches[3])) {
$asset = $matches[3];
}
} }
$data = [ $data = [
@@ -437,7 +468,7 @@ class Assets
} }
$key = md5($asset); $key = md5($asset);
if (is_string($asset) && !array_key_exists($key, $this->inline_js)) { if ($asset && is_string($asset) && !array_key_exists($key, $this->inline_js)) {
$this->inline_js[$key] = $data; $this->inline_js[$key] = $data;
} }
@@ -447,26 +478,27 @@ class Assets
/** /**
* Build the CSS link tags. * Build the CSS link tags.
* *
* @param string $group name of the group
* @param array $attributes * @param array $attributes
* *
* @return string * @return string
*/ */
public function css($attributes = []) public function css($group = 'head', $attributes = [])
{ {
if (!$this->css) { if (!$this->css && !$this->inline_css) {
return null; return null;
} }
// Sort array by priorities (larger priority first) // Sort array by priorities (larger priority first)
if (self::getGrav()) { if (self::getGrav()) {
usort($this->css, function ($a, $b) { uasort($this->css, function ($a, $b) {
if ($a['priority'] == $b['priority']) { if ($a['priority'] == $b['priority']) {
return $b['order'] - $a['order']; return $b['order'] - $a['order'];
} }
return $a['priority'] - $b['priority']; return $a['priority'] - $b['priority'];
}); });
usort($this->inline_css, function ($a, $b) { uasort($this->inline_css, function ($a, $b) {
if ($a['priority'] == $b['priority']) { if ($a['priority'] == $b['priority']) {
return $b['order'] - $a['order']; return $b['order'] - $a['order'];
} }
@@ -479,29 +511,37 @@ class Assets
$attributes = $this->attributes(array_merge(['type' => 'text/css', 'rel' => 'stylesheet'], $attributes)); $attributes = $this->attributes(array_merge(['type' => 'text/css', 'rel' => 'stylesheet'], $attributes));
$output = ''; $output = '';
$inline_css = '';
if ($this->css_pipeline) { if ($this->css_pipeline) {
$pipeline_result = $this->pipelineCss(); $pipeline_result = $this->pipelineCss($group);
if ($pipeline_result) { if ($pipeline_result) {
$output .= '<link href="' . $pipeline_result . '"' . $attributes . ' />' . "\n"; $output .= '<link href="' . $pipeline_result . '"' . $attributes . ' />' . "\n";
} }
foreach ($this->css_no_pipeline as $file) { foreach ($this->css_no_pipeline as $file) {
$media = isset($file['media']) ? sprintf(' media="%s"', $file['media']) : ''; if ($group && $file['group'] == $group) {
$output .= '<link href="' . $file['asset'] . $this->timestamp . '"' . $attributes . $media . ' />' . "\n"; $media = isset($file['media']) ? sprintf(' media="%s"', $file['media']) : '';
$output .= '<link href="' . $file['asset'] . $this->timestamp . '"' . $attributes . $media . ' />' . "\n";
}
} }
} else { } else {
foreach ($this->css as $file) { foreach ($this->css as $file) {
$media = isset($file['media']) ? sprintf(' media="%s"', $file['media']) : ''; if ($group && $file['group'] == $group) {
$output .= '<link href="' . $file['asset'] . $this->timestamp . '"' . $attributes . $media . ' />' . "\n"; $media = isset($file['media']) ? sprintf(' media="%s"', $file['media']) : '';
$output .= '<link href="' . $file['asset'] . $this->timestamp . '"' . $attributes . $media . ' />' . "\n";
}
} }
} }
// Render Inline CSS // Render Inline CSS
if (count($this->inline_css) > 0) { foreach ($this->inline_css as $inline) {
$output .= "<style>\n"; if ($group && $inline['group'] == $group) {
foreach ($this->inline_css as $inline) { $inline_css .= $inline['asset'] . "\n";
$output .= $inline['asset'] . "\n";
} }
$output .= "</style>\n"; }
if ($inline_css) {
$output .= "\n<style>\n" . $inline_css . "\n</style>\n";
} }
@@ -518,19 +558,19 @@ class Assets
*/ */
public function js($group = 'head', $attributes = []) public function js($group = 'head', $attributes = [])
{ {
if (!$this->js) { if (!$this->js && !$this->inline_js) {
return null; return null;
} }
// Sort array by priorities (larger priority first) // Sort array by priorities (larger priority first)
usort($this->js, function ($a, $b) { uasort($this->js, function ($a, $b) {
if ($a['priority'] == $b['priority']) { if ($a['priority'] == $b['priority']) {
return $b['order'] - $a['order']; return $b['order'] - $a['order'];
} }
return $a['priority'] - $b['priority']; return $a['priority'] - $b['priority'];
}); });
usort($this->inline_js, function ($a, $b) { uasort($this->inline_js, function ($a, $b) {
if ($a['priority'] == $b['priority']) { if ($a['priority'] == $b['priority']) {
return $b['order'] - $a['order']; return $b['order'] - $a['order'];
} }
@@ -582,7 +622,7 @@ class Assets
* *
* @return string * @return string
*/ */
protected function pipelineCss() protected function pipelineCss($group = 'head')
{ {
/** @var Cache $cache */ /** @var Cache $cache */
$cache = self::getGrav()['cache']; $cache = self::getGrav()['cache'];
@@ -594,10 +634,10 @@ class Assets
// clear no-pipeline assets lists // clear no-pipeline assets lists
$this->css_no_pipeline = []; $this->css_no_pipeline = [];
$file = md5(json_encode($this->css) . $this->css_minify . $this->css_rewrite) . '.css'; $file = md5(json_encode($this->css) . $this->css_minify . $this->css_rewrite . $group) . '.css';
$relative_path = "{$this->base_url}" . basename(ASSETS_DIR) . "/{$file}"; $relative_path = "{$this->base_url}{$this->assets_url}/{$file}";
$absolute_path = ASSETS_DIR . $file; $absolute_path = $this->assets_dir . $file;
// If pipeline exist return it // If pipeline exist return it
if (file_exists($absolute_path)) { if (file_exists($absolute_path)) {
@@ -606,10 +646,12 @@ class Assets
// Remove any non-pipeline files // Remove any non-pipeline files
foreach ($this->css as $id => $asset) { foreach ($this->css as $id => $asset) {
if (!$asset['pipeline']) { if ($asset['group'] == $group) {
$this->css_no_pipeline[$id] = $asset; if (!$asset['pipeline']) {
} else { $this->css_no_pipeline[$id] = $asset;
$temp_css[$id] = $asset; } else {
$temp_css[$id] = $asset;
}
} }
} }
@@ -662,8 +704,8 @@ class Assets
$file = md5(json_encode($this->js) . $this->js_minify . $group) . '.js'; $file = md5(json_encode($this->js) . $this->js_minify . $group) . '.js';
$relative_path = "{$this->base_url}" . basename(ASSETS_DIR) . "/{$file}"; $relative_path = "{$this->base_url}{$this->assets_url}/{$file}";
$absolute_path = ASSETS_DIR . $file; $absolute_path = $this->assets_dir . $file;
// If pipeline exist return it // If pipeline exist return it
if (file_exists($absolute_path)) { if (file_exists($absolute_path)) {
@@ -825,12 +867,12 @@ class Assets
public function addDir($directory, $pattern = self::DEFAULT_REGEX) public function addDir($directory, $pattern = self::DEFAULT_REGEX)
{ {
// Check if public_dir exists // Check if public_dir exists
if (!is_dir(ASSETS_DIR)) { if (!is_dir($this->assets_dir)) {
throw new Exception('Assets: Public dir not found'); throw new Exception('Assets: Public dir not found');
} }
// Get files // Get files
$files = $this->rglob(ASSETS_DIR . DIRECTORY_SEPARATOR . $directory, $pattern, ASSETS_DIR); $files = $this->rglob($this->assets_dir . DIRECTORY_SEPARATOR . $directory, $pattern, $this->assets_dir);
// No luck? Nothing to do // No luck? Nothing to do
if (!$files) { if (!$files) {
@@ -930,6 +972,7 @@ class Assets
* Download and concatenate the content of several links. * Download and concatenate the content of several links.
* *
* @param array $links * @param array $links
* @param bool $css
* *
* @return string * @return string
*/ */
@@ -960,7 +1003,12 @@ class Assets
$link = ROOT_DIR . $relative_path; $link = ROOT_DIR . $relative_path;
} }
$file = ($this->fetch_command instanceof Closure) ? $this->fetch_command->__invoke($link) : file_get_contents($link); $file = ($this->fetch_command instanceof Closure) ? @$this->fetch_command->__invoke($link) : @file_get_contents($link);
// No file found, skip it...
if ($file === false) {
continue;
}
// Double check last character being // Double check last character being
if (!$css) { if (!$css) {
@@ -1084,6 +1132,36 @@ class Assets
return $this->addDir($directory, self::JS_REGEX); 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() public function __toString()
{ {
return ''; return '';

View File

@@ -64,6 +64,8 @@ class ZipBackup
$zip = new \ZipArchive(); $zip = new \ZipArchive();
$zip->open($destination, \ZipArchive::CREATE); $zip->open($destination, \ZipArchive::CREATE);
$max_execution_time = ini_set('max_execution_time', 600);
static::folderToZip(GRAV_ROOT, $zip, strlen(rtrim(GRAV_ROOT, DS) . DS), $messager); static::folderToZip(GRAV_ROOT, $zip, strlen(rtrim(GRAV_ROOT, DS) . DS), $messager);
$messager && $messager([ $messager && $messager([
@@ -85,6 +87,10 @@ class ZipBackup
$zip->close(); $zip->close();
if ($max_execution_time !== false) {
ini_set('max_execution_time', $max_execution_time);
}
return $destination; return $destination;
} }

View File

@@ -21,6 +21,8 @@ use Grav\Common\Filesystem\Folder;
*/ */
class Cache extends Getters class Cache extends Getters
{ {
use GravTrait;
/** /**
* @var string Cache key. * @var string Cache key.
*/ */
@@ -36,6 +38,10 @@ class Cache extends Getters
*/ */
protected $driver; protected $driver;
protected $driver_name;
protected $driver_setting;
/** /**
* @var bool * @var bool
*/ */
@@ -44,30 +50,30 @@ class Cache extends Getters
protected $cache_dir; protected $cache_dir;
protected static $standard_remove = [ protected static $standard_remove = [
'cache/twig/', 'cache://twig/',
'cache/doctrine/', 'cache://doctrine/',
'cache/compiled/', 'cache://compiled/',
'cache/validated-', 'cache://validated-',
'images/', 'cache://images',
'assets/', 'asset://',
]; ];
protected static $all_remove = [ protected static $all_remove = [
'cache/', 'cache://',
'images/', 'cache://images',
'assets/' 'asset://'
]; ];
protected static $assets_remove = [ protected static $assets_remove = [
'assets/' 'asset://'
]; ];
protected static $images_remove = [ protected static $images_remove = [
'images/' 'cache://images'
]; ];
protected static $cache_remove = [ protected static $cache_remove = [
'cache/' 'cache://'
]; ];
/** /**
@@ -104,10 +110,16 @@ class Cache extends Getters
// Cache key allows us to invalidate all cache on configuration changes. // Cache key allows us to invalidate all cache on configuration changes.
$this->key = ($prefix ? $prefix : 'g') . '-' . substr(md5($uri->rootUrl(true) . $this->config->key() . GRAV_VERSION), 2, 8); $this->key = ($prefix ? $prefix : 'g') . '-' . substr(md5($uri->rootUrl(true) . $this->config->key() . GRAV_VERSION), 2, 8);
$this->driver_setting = $this->config->get('system.cache.driver');
$this->driver = $this->getCacheDriver(); $this->driver = $this->getCacheDriver();
// Set the cache namespace to our unique key // Set the cache namespace to our unique key
$this->driver->setNamespace($this->key); $this->driver->setNamespace($this->key);
// Dump Cache state
$grav['debugger']->addMessage('Cache: [' . ($this->enabled ? 'true' : 'false') . '] Setting: [' . $this->driver_setting . '] Driver: [' . $this->driver_name . ']');
} }
/** /**
@@ -119,11 +131,13 @@ class Cache extends Getters
*/ */
public function getCacheDriver() public function getCacheDriver()
{ {
$setting = $this->config->get('system.cache.driver'); $setting = $this->driver_setting;
$driver_name = 'file'; $driver_name = 'file';
if (!$setting || $setting == 'auto') { if (!$setting || $setting == 'auto') {
if (extension_loaded('apc')) { if (extension_loaded('apcu')) {
$driver_name = 'apcu';
} elseif (extension_loaded('apc')) {
$driver_name = 'apc'; $driver_name = 'apc';
} elseif (extension_loaded('wincache')) { } elseif (extension_loaded('wincache')) {
$driver_name = 'wincache'; $driver_name = 'wincache';
@@ -134,11 +148,17 @@ class Cache extends Getters
$driver_name = $setting; $driver_name = $setting;
} }
$this->driver_name = $driver_name;
switch ($driver_name) { switch ($driver_name) {
case 'apc': case 'apc':
$driver = new \Doctrine\Common\Cache\ApcCache(); $driver = new \Doctrine\Common\Cache\ApcCache();
break; break;
case 'apcu':
$driver = new \Doctrine\Common\Cache\ApcuCache();
break;
case 'wincache': case 'wincache':
$driver = new \Doctrine\Common\Cache\WinCacheCache(); $driver = new \Doctrine\Common\Cache\WinCacheCache();
break; break;
@@ -221,7 +241,7 @@ class Cache extends Getters
*/ */
public static function clearCache($remove = 'standard') public static function clearCache($remove = 'standard')
{ {
$locator = self::getGrav()['locator'];
$output = []; $output = [];
$user_config = USER_DIR . 'config/system.yaml'; $user_config = USER_DIR . 'config/system.yaml';
@@ -243,10 +263,16 @@ class Cache extends Getters
} }
foreach ($remove_paths as $path) { foreach ($remove_paths as $stream) {
// Convert stream to a real path
$path = $locator->findResource($stream, true, true);
// Make sure path exists before proceeding, otherwise we would wipe ROOT_DIR
if (!$path)
throw new \RuntimeException("Stream '{$stream}' not found", 500);
$anything = false; $anything = false;
$files = glob(ROOT_DIR . $path . '*'); $files = glob($path . '/*');
if (is_array($files)) { if (is_array($files)) {
foreach ($files as $file) { foreach ($files as $file) {
@@ -263,7 +289,7 @@ class Cache extends Getters
} }
if ($anything) { if ($anything) {
$output[] = '<red>Cleared: </red>' . $path . '*'; $output[] = '<red>Cleared: </red>' . $path . '/*';
} }
} }

View File

@@ -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];
}
}

View File

@@ -0,0 +1,238 @@
<?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']);
$this->finalizeObject();
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();
}
}

View 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();
}
}

View 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();
}
}

View 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();
}
}

View File

@@ -1,12 +1,10 @@
<?php <?php
namespace Grav\Common\Config; namespace Grav\Common\Config;
use Grav\Common\File\CompiledYamlFile; use Grav\Common\Debugger;
use Grav\Common\Grav; use Grav\Common\Grav;
use Grav\Common\Data\Data; use Grav\Common\Data\Data;
use RocketTheme\Toolbox\Blueprints\Blueprints; use Grav\Common\Service\ConfigServiceProvider;
use RocketTheme\Toolbox\File\PhpFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/** /**
* The Config class contains configuration information. * The Config class contains configuration information.
@@ -16,464 +14,84 @@ use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
*/ */
class Config extends Data class Config extends Data
{ {
protected $grav;
protected $streams = [
'system' => [
'type' => 'ReadOnlyStream',
'prefixes' => [
'' => ['system'],
]
],
'user' => [
'type' => 'ReadOnlyStream',
'prefixes' => [
'' => ['user'],
]
],
'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 $checksum;
protected $timestamp; protected $modified = false;
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();
}
public function key() public function key()
{ {
return $this->checksum(); return $this->checksum();
} }
public function reload() public function checksum($checksum = null)
{ {
$this->items = $this->setup; if ($checksum !== null) {
$this->check(); $this->checksum = $checksum;
$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]));
} }
return $this->checksum; return $this->checksum;
} }
protected function autoDetectEnvironmentConfig($items) public function modified($modified = null)
{ {
$environment = $this->environment; if ($modified !== null) {
$env_stream = 'user://'.$environment.'/config'; $this->modified = $modified;
if (file_exists(USER_DIR.$environment.'/config')) {
array_unshift($items['streams']['schemes']['config']['prefixes'][''], $env_stream);
} }
return $items; return $this->modified;
} }
protected function loadCompiledBlueprints($blueprints, $plugins, $filename = null) public function reload()
{ {
$checksum = md5(json_encode($blueprints)); $grav = Grav::instance();
$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);
// Load real file if cache isn't up to date (or is invalid). // Load new configuration.
if ( $config = ConfigServiceProvider::load($grav);
!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 blueprints. /** @var Debugger $debugger */
$this->blueprints = new Blueprints; $debugger = $grav['debugger'];
foreach ($blueprintFiles as $files) {
$this->loadBlueprintFiles($files);
}
$cache = [ if ($config->modified()) {
'@class' => $class, // Update current configuration.
'checksum' => $checksum, $this->items = $config->toArray();
'files' => $blueprintFiles, $this->checksum($config->checksum());
'data' => $this->blueprints->toArray() $this->modified(true);
];
// If compiled file wasn't already locked by another process, save it. $debugger->addMessage('Configuration was changed and saved.');
if ($file->locked() !== false) { }
$this->messages[] = 'Saving compiled blueprints.';
$file->save($cache); return $this;
$file->unlock(); }
}
} else { public function debug()
$this->blueprints = new Blueprints($cache['data']); {
/** @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()
{ {
$filename = $filename $setup = Grav::instance()['setup']->toArray();
? CACHE_DIR . 'compiled/config/' . $filename . '-' . $this->environment . '.php' foreach ($setup as $key => $value) {
: CACHE_DIR . 'compiled/config/' . $checksum . '-' . $this->environment . '.php'; if ($key === 'streams' || !is_array($value)) {
$file = PhpFile::instance($filename); // Optimized as streams and simple values are fully defined in setup.
$cache = $file->exists() ? $file->content() : null; $this->items[$key] = $value;
$class = get_class($this); } else {
$checksum = $this->checksum(); $this->joinDefaults($key, $value);
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);
}
} }
} }
} }
/** /**
* Get available streams and their types from the configuration. * @return mixed
* * @deprecated
* @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;
}
public function getLanguages() public function getLanguages()
{ {
return $this->languages; return Grav::instance()['languages'];
} }
} }

View 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;
}
}

View File

@@ -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];
}
}

View File

@@ -11,6 +11,23 @@ use Grav\Common\Data\Data;
*/ */
class Languages extends 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() public function reformat()
{ {

View 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();
}
}
}

View File

@@ -3,6 +3,8 @@ namespace Grav\Common\Data;
use Grav\Common\GravTrait; use Grav\Common\GravTrait;
use RocketTheme\Toolbox\ArrayTraits\Export; use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
/** /**
* Blueprint handles the inside logic of blueprints. * Blueprint handles the inside logic of blueprints.
@@ -10,9 +12,9 @@ use RocketTheme\Toolbox\ArrayTraits\Export;
* @author RocketTheme * @author RocketTheme
* @license MIT * @license MIT
*/ */
class Blueprint class Blueprint implements \ArrayAccess, ExportInterface
{ {
use Export, DataMutatorTrait, GravTrait; use Export, NestedArrayAccessWithGetters, GravTrait;
public $name; public $name;
@@ -76,7 +78,9 @@ class Blueprint
try { try {
$this->validateArray($data, $this->nested); $this->validateArray($data, $this->nested);
} catch (\RuntimeException $e) { } catch (\RuntimeException $e) {
throw new \RuntimeException(sprintf('<b>Validation failed:</b> %s', $e->getMessage())); $language = self::getGrav()['language'];
$message = sprintf($language->translate('FORM.VALIDATION_FAIL', null, true) . ' %s', $e->getMessage());
throw new \RuntimeException($message);
} }
} }
@@ -238,9 +242,6 @@ class Blueprint
if ($rule) { if ($rule) {
// Item has been defined in blueprints. // Item has been defined in blueprints.
if (is_array($field) && count($field) == 1 && reset($field) == '') {
continue;
}
$field = Validation::filter($field, $rule); $field = Validation::filter($field, $rule);
} elseif (is_array($field) && is_array($val)) { } elseif (is_array($field) && is_array($val)) {
// Array has been defined in blueprints. // Array has been defined in blueprints.
@@ -310,91 +311,107 @@ class Blueprint
} }
/** /**
* Gets all field definitions from the blueprints. * Gets all field definitions from the blueprints.
* *
* @param array $fields * @param array $fields
* @param array $params * @param array $params
* @param string $prefix * @param string $prefix
* @param array $current * @param array $current
* @internal * @internal
*/ */
protected function parseFormFields(array &$fields, $params, $prefix, array &$current) protected function parseFormFields(array &$fields, $params, $prefix, array &$current)
{ {
// Go though all the fields in current level. // Go though all the fields in current level.
foreach ($fields as $key => &$field) { foreach ($fields as $key => &$field) {
$current[$key] = &$field; $current[$key] = &$field;
// Set name from the array key. // Set name from the array key.
$field['name'] = $prefix . $key; $field['name'] = $prefix . $key;
$field += $params; $field += $params;
if (isset($field['fields']) && (!isset($field['type']) || $field['type'] !== 'list')) { if (isset($field['fields']) && (!isset($field['type']) || $field['type'] !== 'list')) {
// Recursively get all the nested fields. // Recursively get all the nested fields.
$newParams = array_intersect_key($this->filter, $field); $newParams = array_intersect_key($this->filter, $field);
$this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']); $this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']);
} else if ($field['type'] !== 'ignore') { } else if ($field['type'] !== 'ignore') {
// Add rule.
$this->rules[$prefix . $key] = &$field; $this->rules[$prefix . $key] = &$field;
$this->addProperty($prefix . $key); $this->addProperty($prefix . $key);
foreach ($field as $name => $value) { if ($field['type'] === 'list') {
// Support nested blueprints. // we loop through list to get the actual field
if ($this->context && $name == '@import') { if (isset($field['fields']) && $field['fields']) {
$values = (array) $value; foreach($field['fields'] as $subName => &$subField) {
if (!isset($field['fields'])) { $this->parseFormField($subField);
$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;
} }
} }
} else {
$this->parseFormField($field);
} }
// Initialize predefined validation rule.
if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') { if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') {
$field['validate'] += $this->getRule($field['validate']['rule']); $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. * Add property to the definition.
@@ -449,7 +466,10 @@ class Blueprint
if (isset($field['validate']['required']) if (isset($field['validate']['required'])
&& $field['validate']['required'] === true && $field['validate']['required'] === true
&& empty($data[$name])) { && empty($data[$name])) {
throw new \RuntimeException("Missing required field: {$field['name']}"); $value = isset($field['label']) ? $field['label'] : $field['name'];
$language = self::getGrav()['language'];
$message = sprintf($language->translate('FORM.MISSING_REQUIRED_FIELD', null, true) . ' %s', $value);
throw new \RuntimeException($message);
} }
} }
} }

View File

@@ -1,9 +1,11 @@
<?php <?php
namespace Grav\Common\Data; namespace Grav\Common\Data;
use RocketTheme\Toolbox\ArrayTraits\ArrayAccessWithGetters;
use RocketTheme\Toolbox\ArrayTraits\Countable; use RocketTheme\Toolbox\ArrayTraits\Countable;
use RocketTheme\Toolbox\ArrayTraits\Export; 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\File;
use RocketTheme\Toolbox\File\FileInterface; use RocketTheme\Toolbox\File\FileInterface;
@@ -13,9 +15,9 @@ use RocketTheme\Toolbox\File\FileInterface;
* @author RocketTheme * @author RocketTheme
* @license MIT * @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 $gettersVariable = 'items';
protected $items; protected $items;
@@ -32,12 +34,11 @@ class Data implements DataInterface
/** /**
* @param array $items * @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->items = $items;
$this->blueprints = $blueprints; $this->blueprints = $blueprints;
} }
@@ -57,126 +58,150 @@ class Data implements DataInterface
} }
/** /**
* Set default value by using dot notation for nested arrays/objects. * Join nested values together by using blueprints.
*
* @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.
* *
* @param string $name Dot separated path to the requested value. * @param string $name Dot separated path to the requested value.
* @param mixed $value Value to be joined. * @param mixed $value Value to be joined.
* @param string $separator Separator, defaults to '.' * @param string $separator Separator, defaults to '.'
* @return $this
* @throws \RuntimeException
*/ */
public function join($name, $value, $separator = '.') public function join($name, $value, $separator = '.')
{ {
$old = $this->get($name, null, $separator); $old = $this->get($name, null, $separator);
if ($old === null) { if ($old !== null) {
// Variable does not exist yet: just use the incoming value. if (!is_array($old)) {
} elseif ($this->blueprints) { throw new \RuntimeException('Value ' . $old);
// Blueprints: join values by using blueprints. }
$value = $this->blueprints->mergeData($old, $value, $name, $separator); if (is_object($value)) {
} else { $value = (array) $value;
// No blueprints: replace existing top level variables with the new ones. } elseif (!is_array($value)) {
$value = array_merge($old, $value); throw new \RuntimeException('Value ' . $value);
}
$value = $this->blueprints()->mergeData($old, $value, $name, $separator);
} }
$this->set($name, $value, $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 string $name Dot separated path to the requested value.
* @param mixed $value Value to be joined. * @param mixed $value Value to be joined.
* @param string $separator Separator, defaults to '.' * @param string $separator Separator, defaults to '.'
* @return $this
*/ */
public function joinDefaults($name, $value, $separator = '.') public function joinDefaults($name, $value, $separator = '.')
{ {
if (is_object($value)) {
$value = (array) $value;
}
$old = $this->get($name, null, $separator); $old = $this->get($name, null, $separator);
if ($old === null) { if ($old !== null) {
// Variable does not exist yet: just use the incoming value. $value = $this->blueprints()->mergeData($value, $old, $name, $separator);
} 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);
} }
$this->set($name, $value, $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 * @param array $data
* @return void * @return $this
*/ */
public function merge(array $data) public function merge(array $data)
{ {
if ($this->blueprints) { $this->items = $this->blueprints()->mergeData($this->items, $data);
$this->items = $this->blueprints->mergeData($this->items, $data);
} else { return $this;
$this->items = array_merge($this->items, $data);
}
} }
/** /**
* Add default data to the set. * Set default values to the configuration if variables were not set.
* *
* @param array $data * @param array $data
* @return void * @return $this
*/ */
public function setDefaults(array $data) public function setDefaults(array $data)
{ {
if ($this->blueprints) { $this->items = $this->blueprints()->mergeData($data, $this->items);
$this->items = $this->blueprints->mergeData($data, $this->items);
} else {
$this->items = array_merge($data, $this->items);
}
}
/** return $this;
* Return blueprints.
*
* @return Blueprint
*/
public function blueprints()
{
return $this->blueprints;
} }
/** /**
* Validate by blueprints. * Validate by blueprints.
* *
* @return $this
* @throws \Exception * @throws \Exception
*/ */
public function validate() 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. * Filter all items by using blueprints.
*/ */
public function filter() public function filter()
{ {
if ($this->blueprints) { $this->items = $this->blueprints()->filter($this->items);
$this->items = $this->blueprints->filter($this->items);
} return $this;
} }
/** /**
@@ -189,6 +214,23 @@ class Data implements DataInterface
return $this->blueprints ? $this->blueprints->extra($this->items) : array(); return $this->blueprints ? $this->blueprints->extra($this->items) : array();
} }
/**
* 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;
}
/** /**
* Save data if storage has been defined. * Save data if storage has been defined.
*/ */

View File

@@ -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;
}
}

View File

@@ -1,5 +1,6 @@
<?php <?php
namespace Grav\Common\Data; namespace Grav\Common\Data;
use Grav\Common\GravTrait; use Grav\Common\GravTrait;
use Symfony\Component\Yaml\Exception\ParseException; use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser; use Symfony\Component\Yaml\Parser;
@@ -30,14 +31,19 @@ class Validation
return; 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 // Get language class
$language = self::getGrav()['language']; $language = self::getGrav()['language'];
// Validate type with fallback type text. // Validate type with fallback type text.
$type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type']; $type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type'];
$method = 'type'.strtr($type, '-', '_'); $method = 'type'.strtr($type, '-', '_');
$name = ucfirst($field['label'] ? $field['label'] : $field['name']); $name = ucfirst(isset($field['label']) ? $field['label'] : $field['name']);
$message = (string) isset($field['validate']['message']) ? $field['validate']['message'] : 'Invalid input in "' . $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)) { if (method_exists(__CLASS__, $method)) {
$success = self::$method($value, $validate, $field); $success = self::$method($value, $validate, $field);
@@ -77,6 +83,11 @@ class Validation
return null; 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 this is a YAML field, simply parse it and return the value
if (isset($field['yaml']) && $field['yaml'] === true) { if (isset($field['yaml']) && $field['yaml'] === true) {
try { try {
@@ -257,6 +268,32 @@ class Validation
return self::typeArray((array) $value, $params, $field); 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)
{
if (isset($field['multiple']) && $field['multiple'] == true) {
return (array) $value;
}
if (is_array($value)) {
return reset($value);
}
return $value;
}
/** /**
* HTML5 input: select * HTML5 input: select
* *
@@ -588,6 +625,10 @@ class Validation
public static function validateRequired($value, $params) public static function validateRequired($value, $params)
{ {
if (is_string($value)) {
$value = trim($value);
}
return (bool) $params !== true || !empty($value); return (bool) $params !== true || !empty($value);
} }

View File

@@ -15,6 +15,8 @@ class Debugger
protected $renderer; protected $renderer;
protected $enabled; protected $enabled;
protected $timers = [];
public function __construct() public function __construct()
{ {
$this->debugbar = new StandardDebugBar(); $this->debugbar = new StandardDebugBar();
@@ -26,7 +28,8 @@ class Debugger
$this->grav = Grav::instance(); $this->grav = Grav::instance();
if ($this->enabled()) { if ($this->enabled()) {
$this->debugbar->addCollector(new \DebugBar\DataCollector\ConfigCollector((array)$this->grav['config']->get('system'))); $this->debugbar->addCollector(new \DebugBar\DataCollector\ConfigCollector((array)$this->grav['config']->get('system'), 'Config'));
$this->debugbar->addCollector(new \DebugBar\DataCollector\ConfigCollector((array)$this->grav['config']->get('plugins'), 'Plugins'));
} }
return $this; return $this;
} }
@@ -98,15 +101,17 @@ class Debugger
{ {
if ($name[0] == '_' || $this->grav['config']->get('system.debugger.enabled')) { if ($name[0] == '_' || $this->grav['config']->get('system.debugger.enabled')) {
$this->debugbar['time']->startMeasure($name, $description); $this->debugbar['time']->startMeasure($name, $description);
$this->timers[] = $name;
} }
return $this; return $this;
} }
public function stopTimer($name) public function stopTimer($name)
{ {
if ($name[0] == '_' || $this->grav['config']->get('system.debugger.enabled')) { if (in_array($name, $this->timers) && ($name[0] == '_' || $this->grav['config']->get('system.debugger.enabled'))) {
$this->debugbar['time']->stopMeasure($name); $this->debugbar['time']->stopMeasure($name);
} }
return $this; return $this;
} }

View File

@@ -2,51 +2,54 @@
namespace Grav\Common\Errors; namespace Grav\Common\Errors;
use Grav\Common\Grav; use Grav\Common\Grav;
use Whoops\Handler\CallbackHandler; use Whoops;
use Whoops\Handler\HandlerInterface;
use Whoops\Run;
/** /**
* Class Debugger * Class Debugger
* @package Grav\Common * @package Grav\Common
*/ */
class Errors extends \Whoops\Run class Errors
{ {
public function pushHandler($handler, $key = null)
{
if (is_callable($handler)) {
$handler = new CallbackHandler($handler);
}
if (!$handler instanceof HandlerInterface) {
throw new \InvalidArgumentException(
"Argument to " . __METHOD__ . " must be a callable, or instance of"
. "Whoops\\Handler\\HandlerInterface"
);
}
// Store with key if provided
if ($key) {
$this->handlerStack[$key] = $handler;
} else {
$this->handlerStack[] = $handler;
}
return $this;
}
public function resetHandlers() public function resetHandlers()
{ {
$grav = Grav::instance(); $grav = Grav::instance();
$config = $grav['config']->get('system.errors'); $config = $grav['config']->get('system.errors');
if (isset($config['display']) && !$config['display']) {
unset($this->handlerStack['pretty']);
$this->handlerStack = array('simple' => new SimplePageHandler()) + $this->handlerStack;
}
if (isset($config['log']) && !$config['log']) {
unset($this->handlerStack['log']);
}
}
// Setup Whoops-based error handler
$whoops = new \Whoops\Run;
if (isset($config['display'])) {
if ($config['display']) {
$error_page = new Whoops\Handler\PrettyPageHandler;
$error_page->setPageTitle('Crikey! There was an error...');
$error_page->addResourcePath(GRAV_ROOT . '/system/assets');
$error_page->addCustomCss('whoops.css');
$whoops->pushHandler($error_page);
} else {
$whoops->pushHandler(new SimplePageHandler);
}
}
if (function_exists('Whoops\isAjaxRequest')) { //Whoops 2
if (Whoops\isAjaxRequest()) {
$whoops->pushHandler(new Whoops\Handler\JsonResponseHandler);
}
} else { //Whoops 1
$json_page = new Whoops\Handler\JsonResponseHandler;
$json_page->onlyForAjaxRequests(true);
}
if (isset($config['log']) && $config['log']) {
$logger = $grav['log'];
$whoops->pushHandler(function($exception, $inspector, $run) use ($logger) {
try {
$logger->addCritical($exception->getMessage() . ' - Trace: ' . $exception->getTraceAsString());
} catch (\Exception $e) {
echo $e;
}
}, 'log');
}
$whoops->register();
}
} }

View File

@@ -47,7 +47,11 @@ trait CompiledFile
|| $cache['filename'] != $this->filename || $cache['filename'] != $this->filename
) { ) {
// Attempt to lock the file for writing. // 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. // Decode RAW file into compiled array.
$data = (array) $this->decode($this->raw()); $data = (array) $this->decode($this->raw());
@@ -64,6 +68,7 @@ trait CompiledFile
$file->unlock(); $file->unlock();
} }
} }
$file->free();
$this->content = $cache['data']; $this->content = $cache['data'];
} }

View File

@@ -19,12 +19,12 @@ abstract class Folder
{ {
$last_modified = 0; $last_modified = 0;
$dirItr = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS); $directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
$filterItr = new RecursiveFolderFilterIterator($dirItr); $filter = new RecursiveFolderFilterIterator($directory);
$itr = new \RecursiveIteratorIterator($filterItr, \RecursiveIteratorIterator::SELF_FIRST); $iterator = new \RecursiveIteratorIterator($filter, \RecursiveIteratorIterator::SELF_FIRST);
/** @var \RecursiveDirectoryIterator $file */ /** @var \RecursiveDirectoryIterator $file */
foreach ($itr as $dir) { foreach ($iterator as $dir) {
$dir_modified = $dir->getMTime(); $dir_modified = $dir->getMTime();
if ($dir_modified > $last_modified) { if ($dir_modified > $last_modified) {
$last_modified = $dir_modified; $last_modified = $dir_modified;
@@ -46,12 +46,12 @@ abstract class Folder
{ {
$last_modified = 0; $last_modified = 0;
$dirItr = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS); $directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
$itrItr = new \RecursiveIteratorIterator($dirItr, \RecursiveIteratorIterator::SELF_FIRST); $recursive = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
$itr = new \RegexIterator($itrItr, '/^.+\.'.$extensions.'$/i'); $iterator = new \RegexIterator($recursive, '/^.+\.'.$extensions.'$/i');
/** @var \RecursiveDirectoryIterator $file */ /** @var \RecursiveDirectoryIterator $file */
foreach ($itr as $filepath => $file) { foreach ($iterator as $filepath => $file) {
$file_modified = $file->getMTime(); $file_modified = $file->getMTime();
if ($file_modified > $last_modified) { if ($file_modified > $last_modified) {
$last_modified = $file_modified; $last_modified = $file_modified;
@@ -81,6 +81,43 @@ abstract class Folder
return $path; 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. * Shift first directory out of the path.
* *
@@ -96,8 +133,6 @@ abstract class Folder
return $result ?: null; return $result ?: null;
} }
/** /**
* Return recursive list of all files and directories under given path. * 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; $pattern = isset($params['pattern']) ? $params['pattern'] : null;
$filters = isset($params['filters']) ? $params['filters'] : null; $filters = isset($params['filters']) ? $params['filters'] : null;
$recursive = isset($params['recursive']) ? $params['recursive'] : true; $recursive = isset($params['recursive']) ? $params['recursive'] : true;
$levels = isset($params['levels']) ? $params['levels'] : -1;
$key = isset($params['key']) ? 'get' . $params['key'] : null; $key = isset($params['key']) ? 'get' . $params['key'] : null;
$value = isset($params['value']) ? 'get' . $params['value'] : ($recursive ? 'getSubPathname' : 'getFilename'); $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) { if ($recursive) {
$directory = new \RecursiveDirectoryIterator($path, $directory = new \RecursiveDirectoryIterator($path,
\RecursiveDirectoryIterator::SKIP_DOTS + \FilesystemIterator::UNIX_PATHS + \FilesystemIterator::CURRENT_AS_SELF); \RecursiveDirectoryIterator::SKIP_DOTS + \FilesystemIterator::UNIX_PATHS + \FilesystemIterator::CURRENT_AS_SELF);
$iterator = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST); $iterator = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
$iterator->setMaxDepth(max($levels, -1));
} else { } else {
$iterator = new \FilesystemIterator($path); $iterator = new \FilesystemIterator($path);
} }
@@ -131,6 +170,16 @@ abstract class Folder
/** @var \RecursiveDirectoryIterator $file */ /** @var \RecursiveDirectoryIterator $file */
foreach ($iterator as $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}())) { if ($compare && $pattern && !preg_match($pattern, $file->{$compare}())) {
continue; continue;
} }
@@ -138,7 +187,8 @@ abstract class Folder
$filePath = $file->{$value}(); $filePath = $file->{$value}();
if ($filters) { if ($filters) {
if (isset($filters['key'])) { 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'])) { if (isset($filters['value'])) {
$filter = $filters['value']; $filter = $filters['value'];
@@ -146,12 +196,12 @@ abstract class Folder
$filePath = call_user_func($filter, $file); $filePath = call_user_func($filter, $file);
} else { } else {
$filePath = preg_replace($filter, '', $filePath); $filePath = preg_replace($filter, '', $filePath);
}
} }
} }
}
if ($fileKey !== null) { if ($fileKey !== null) {
$results[$fileKey] = $filePath; $results[$fileKey] = $filePath;
} else { } else {
$results[] = $filePath; $results[] = $filePath;
} }
@@ -163,11 +213,12 @@ abstract class Folder
/** /**
* Recursively copy directory in filesystem. * Recursively copy directory in filesystem.
* *
* @param string $source * @param string $source
* @param string $target * @param string $target
* @param string $ignore Ignore files matching pattern (regular expression).
* @throws \RuntimeException * @throws \RuntimeException
*/ */
public static function copy($source, $target) public static function copy($source, $target, $ignore = null)
{ {
$source = rtrim($source, '\\/'); $source = rtrim($source, '\\/');
$target = rtrim($target, '\\/'); $target = rtrim($target, '\\/');
@@ -177,19 +228,24 @@ abstract class Folder
} }
// Make sure that path to the target exists before copying. // Make sure that path to the target exists before copying.
self::mkdir($target); self::create($target);
$success = true; $success = true;
// Go through all sub-directories and copy everything. // Go through all sub-directories and copy everything.
$files = self::all($source); $files = self::all($source);
foreach ($files as $file) { foreach ($files as $file) {
if ($ignore && preg_match($ignore, $file)) {
continue;
}
$src = $source .'/'. $file; $src = $source .'/'. $file;
$dst = $target .'/'. $file; $dst = $target .'/'. $file;
if (is_dir($src)) { if (is_dir($src)) {
// Create current directory. // Create current directory (if it doesn't exist).
$success &= @mkdir($dst); if (!is_dir($dst)) {
$success &= @mkdir($dst, 0777, true);
}
} else { } else {
// Or copy current file. // Or copy current file.
$success &= @copy($src, $dst); $success &= @copy($src, $dst);
@@ -208,8 +264,8 @@ abstract class Folder
/** /**
* Move directory in filesystem. * Move directory in filesystem.
* *
* @param string $source * @param string $source
* @param string $target * @param string $target
* @throws \RuntimeException * @throws \RuntimeException
*/ */
public static function move($source, $target) public static function move($source, $target)
@@ -218,8 +274,13 @@ abstract class Folder
throw new \RuntimeException('Cannot move non-existing 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. // Make sure that path to the target exists before moving.
self::mkdir(dirname($target)); self::create(dirname($target));
// Just rename the directory. // Just rename the directory.
$success = @rename($source, $target); $success = @rename($source, $target);
@@ -238,16 +299,16 @@ abstract class Folder
* Recursively delete directory from filesystem. * Recursively delete directory from filesystem.
* *
* @param string $target * @param string $target
* @throws \RuntimeException * @param bool $include_target
* @return bool * @return bool
*/ */
public static function delete($target) public static function delete($target, $include_target = true)
{ {
if (!is_dir($target)) { if (!is_dir($target)) {
return; return false;
} }
$success = self::doDelete($target); $success = self::doDelete($target, $include_target);
if (!$success) { if (!$success) {
$error = error_get_last(); $error = error_get_last();
@@ -255,16 +316,31 @@ abstract class Folder
} }
// Make sure that the change will be detected when caching. // Make sure that the change will be detected when caching.
@touch(dirname($target)); if ($include_target) {
@touch(dirname($target));
} else {
@touch($target);
}
return $success; return $success;
} }
/** /**
* @param string $folder * @param string $folder
* @throws \RuntimeException * @throws \RuntimeException
* @internal * @internal
*/ */
public static function mkdir($folder) public static function mkdir($folder)
{
self::create($folder);
}
/**
* @param string $folder
* @throws \RuntimeException
* @internal
*/
public static function create($folder)
{ {
if (is_dir($folder)) { if (is_dir($folder)) {
return; return;
@@ -320,10 +396,11 @@ abstract class Folder
/** /**
* @param string $folder * @param string $folder
* @param bool $include_target
* @return bool * @return bool
* @internal * @internal
*/ */
protected static function doDelete($folder) protected static function doDelete($folder, $include_target = true)
{ {
// Special case for symbolic links. // Special case for symbolic links.
if (is_link($folder)) { if (is_link($folder)) {
@@ -338,16 +415,16 @@ abstract class Folder
/** @var \DirectoryIterator $fileinfo */ /** @var \DirectoryIterator $fileinfo */
foreach ($files as $fileinfo) { foreach ($files as $fileinfo) {
if ($fileinfo->isDir()) { if ($fileinfo->isDir()) {
if (false === rmdir($fileinfo->getRealPath())) { if (false === @rmdir($fileinfo->getRealPath())) {
return false; return false;
} }
} else { } else {
if (false === unlink($fileinfo->getRealPath())) { if (false === @unlink($fileinfo->getRealPath())) {
return false; return false;
} }
} }
} }
return rmdir($folder); return $include_target ? @rmdir($folder) : true;
} }
} }

View File

@@ -323,13 +323,24 @@ class GPM extends Iterator
return $found; return $found;
} }
foreach ($this->getRepositoryThemes() as $slug => $theme) { $themes = $this->getRepositoryThemes();
$plugins = $this->getRepositoryPlugins();
if (!$themes && !$plugins) {
if (!is_writable(ROOT_DIR . '/cache/gpm')) {
throw new \RuntimeException("The cache/gpm folder is not writable. Please check the folder permissions.");
}
throw new \RuntimeException("GPM not reachable. Please check your internet connection or check the Grav site is reachable");
}
if ($themes) foreach ($themes as $slug => $theme) {
if ($search == $slug || $search == $theme->name) { if ($search == $slug || $search == $theme->name) {
return $theme; return $theme;
} }
} }
foreach ($this->getRepositoryPlugins() as $slug => $plugin) { if ($plugins) foreach ($plugins as $slug => $plugin) {
if ($search == $slug || $search == $plugin->name) { if ($search == $slug || $search == $plugin->name) {
return $plugin; return $plugin;
} }

View File

@@ -281,6 +281,10 @@ class Installer
{ {
$msg = 'Unknown Error'; $msg = 'Unknown Error';
if (is_string(self::$error)) {
return self::$error;
}
switch (self::$error) { switch (self::$error) {
case 0: case 0:
$msg = 'No Error'; $msg = 'No Error';
@@ -333,7 +337,7 @@ class Installer
/** /**
* Allows to manually set an error * Allows to manually set an error
* @param $error the Error code * @param int|string $error the Error code
*/ */
public static function setError($error) public static function setError($error)

View File

@@ -3,10 +3,9 @@
namespace Grav\Common\GPM\Local; namespace Grav\Common\GPM\Local;
use Grav\Common\GPM\Common\AbstractPackageCollection as BaseCollection; use Grav\Common\GPM\Common\AbstractPackageCollection as BaseCollection;
use Grav\Common\GPM\Local\Package;
abstract class AbstractPackageCollection extends BaseCollection {
abstract class AbstractPackageCollection extends BaseCollection
{
public function __construct($items) public function __construct($items)
{ {
foreach ($items as $name => $data) { foreach ($items as $name => $data) {

View File

@@ -1,58 +0,0 @@
<?php
namespace Grav\Common\GPM;
use Grav\Common\Data\Data;
/**
* Interface Package
* @package Grav\Common\GPM
*/
class Package
{
/**
* @var Data
*/
protected $data;
/**
* @var \Grav\Common\Data\Blueprint
*/
protected $blueprints;
/**
* @param Data $package
* @param bool $package_type
*/
public function __construct(Data $package, $package_type = false);
/**
* @return mixed
*/
public function isEnabled();
/**
* @return Data
*/
public function getData();
/**
* @param $key
* @return mixed
*/
public function __get($key);
/**
* @return string
*/
public function __toString();
/**
* @return string
*/
public function toJson();
/**
* @return array
*/
public function toArray();
}

View File

@@ -3,7 +3,6 @@ namespace Grav\Common\GPM\Remote;
use Grav\Common\GPM\Common\AbstractPackageCollection as BaseCollection; use Grav\Common\GPM\Common\AbstractPackageCollection as BaseCollection;
use Grav\Common\GPM\Response; use Grav\Common\GPM\Response;
use \Doctrine\Common\Cache\FilesystemCache; use \Doctrine\Common\Cache\FilesystemCache;
class AbstractPackageCollection extends BaseCollection class AbstractPackageCollection extends BaseCollection

View File

@@ -5,7 +5,7 @@ use \Doctrine\Common\Cache\FilesystemCache;
class Grav extends AbstractPackageCollection class Grav extends AbstractPackageCollection
{ {
protected $repository = 'http://getgrav.org/downloads/grav.json'; protected $repository = 'https://getgrav.org/downloads/grav.json';
private $data; private $data;
private $version; private $version;
@@ -55,7 +55,7 @@ class Grav extends AbstractPackageCollection
$diffLog = []; $diffLog = [];
foreach ($this->data['changelog'] as $version => $changelog) { 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; } if (!$cleanVersion || version_compare($diff, $cleanVersion[0], ">=")) { continue; }

View File

@@ -12,10 +12,12 @@ class Plugins extends AbstractPackageCollection
*/ */
protected $type = 'plugins'; protected $type = 'plugins';
protected $repository = 'http://getgrav.org/downloads/plugins.json'; protected $repository = 'https://getgrav.org/downloads/plugins.json';
/** /**
* Local Plugins Constructor * Local Plugins Constructor
* @param bool $refresh
* @param callable $callback Either a function or callback in array notation
*/ */
public function __construct($refresh = false, $callback = null) public function __construct($refresh = false, $callback = null)
{ {

View File

@@ -12,10 +12,12 @@ class Themes extends AbstractPackageCollection
*/ */
protected $type = 'themes'; protected $type = 'themes';
protected $repository = 'http://getgrav.org/downloads/themes.json'; protected $repository = 'https://getgrav.org/downloads/themes.json';
/** /**
* Local Themes Constructor * Local Themes Constructor
* @param bool $refresh
* @param callable $callback Either a function or callback in array notation
*/ */
public function __construct($refresh = false, $callback = null) public function __construct($refresh = false, $callback = null)
{ {

View File

@@ -1,27 +1,32 @@
<?php <?php
namespace Grav\Common\GPM; namespace Grav\Common\GPM;
use Grav\Common\Utils;
class Response class Response
{ {
/** /**
* The callback for the progress * The callback for the progress
*
* @var callable Either a function or callback in array notation * @var callable Either a function or callback in array notation
*/ */
public static $callback = null; public static $callback = null;
/** /**
* Which method to use for HTTP calls, can be 'curl', 'fopen' or 'auto'. Auto is default and fopen is the preferred method * Which method to use for HTTP calls, can be 'curl', 'fopen' or 'auto'. Auto is default and fopen is the preferred method
*
* @var string * @var string
*/ */
private static $method = 'auto'; private static $method = 'auto';
/** /**
* Default parameters for `curl` and `fopen` * Default parameters for `curl` and `fopen`
*
* @var array * @var array
*/ */
private static $defaults = [ private static $defaults = [
'curl' => [ 'curl' => [
CURLOPT_REFERER => 'Grav GPM', CURLOPT_REFERER => 'Grav GPM',
CURLOPT_USERAGENT => 'Grav GPM', CURLOPT_USERAGENT => 'Grav GPM',
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
@@ -49,7 +54,10 @@ class Response
/** /**
* Sets the preferred method to use for making HTTP calls. * Sets the preferred method to use for making HTTP calls.
*
* @param string $method Default is `auto` * @param string $method Default is `auto`
*
* @return Response
*/ */
public static function setMethod($method = 'auto') public static function setMethod($method = 'auto')
{ {
@@ -64,8 +72,11 @@ class Response
/** /**
* Makes a request to the URL by using the preferred method * Makes a request to the URL by using the preferred method
* @param string $uri URL to call *
* @param array $options An array of parameters for both `curl` and `fopen` * @param string $uri URL to call
* @param array $options An array of parameters for both `curl` and `fopen`
* @param callable $callback Either a function or callback in array notation
*
* @return string The response of the request * @return string The response of the request
*/ */
public static function get($uri = '', $options = [], $callback = null) public static function get($uri = '', $options = [], $callback = null)
@@ -74,6 +85,14 @@ class Response
throw new \RuntimeException('Could not start an HTTP request. `allow_url_open` is disabled and `cURL` is not available'); throw new \RuntimeException('Could not start an HTTP request. `allow_url_open` is disabled and `cURL` is not available');
} }
// 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); $options = array_replace_recursive(self::$defaults, $options);
$method = 'get' . ucfirst(strtolower(self::$method)); $method = 'get' . ucfirst(strtolower(self::$method));
@@ -81,9 +100,31 @@ class Response
return static::$method($uri, $options, $callback); return static::$method($uri, $options, $callback);
} }
/**
* Checks if cURL is available
*
* @return boolean
*/
public static function isCurlAvailable()
{
return function_exists('curl_version');
}
/**
* Checks if the remote fopen request is enabled in PHP
*
* @return boolean
*/
public static function isFopenAvailable()
{
return preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen'));
}
/** /**
* Progress normalized for cURL and Fopen * Progress normalized for cURL and Fopen
*
* @param args Variable length of arguments passed in by stream method * @param args Variable length of arguments passed in by stream method
*
* @return array Normalized array with useful data. * @return array Normalized array with useful data.
* Format: ['code' => int|false, 'filesize' => bytes, 'transferred' => bytes, 'percent' => int] * Format: ['code' => int|false, 'filesize' => bytes, 'transferred' => bytes, 'percent' => int]
*/ */
@@ -104,7 +145,7 @@ class Response
} }
if ($bytes_transferred > 0) { if ($bytes_transferred > 0) {
if ($notification_code == STREAM_NOTIFY_PROGRESS|STREAM_NOTIFY_COMPLETED || $isCurlResource) { if ($notification_code == STREAM_NOTIFY_PROGRESS | STREAM_NOTIFY_COMPLETED || $isCurlResource) {
$progress = [ $progress = [
'code' => $notification_code, 'code' => $notification_code,
@@ -120,31 +161,14 @@ class Response
} }
} }
/**
* Checks if cURL is available
* @return boolean
*/
public static function isCurlAvailable()
{
return function_exists('curl_version');
}
/**
* Checks if the remote fopen request is enabled in PHP
* @return boolean
*/
public static function isFopenAvailable()
{
return preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen'));
}
/** /**
* Automatically picks the preferred method * Automatically picks the preferred method
*
* @return string The response of the request * @return string The response of the request
*/ */
private static function getAuto() private static function getAuto()
{ {
if (self::isFopenAvailable()) { if (!ini_get('open_basedir') && self::isFopenAvailable()) {
return self::getFopen(func_get_args()); return self::getFopen(func_get_args());
} }
@@ -153,46 +177,9 @@ class Response
} }
} }
/**
* Starts a HTTP request via cURL
* @return string The response of the request
*/
private static function getCurl()
{
$args = func_get_args();
$args = count($args) > 1 ? $args : array_shift($args);
$uri = $args[0];
$options = $args[1];
$callback = $args[2];
$ch = curl_init($uri);
curl_setopt_array($ch, $options['curl']);
if ($callback) {
curl_setopt_array(
$ch,
[
CURLOPT_NOPROGRESS => false,
CURLOPT_PROGRESSFUNCTION => ['self', 'progress']
]
);
}
$response = curl_exec($ch);
if ($errno = curl_errno($ch)) {
$error_message = curl_strerror($errno);
throw new \RuntimeException("cURL error ({$errno}):\n {$error_message}");
}
curl_close($ch);
return $response;
}
/** /**
* Starts a HTTP request via fopen * Starts a HTTP request via fopen
*
* @return string The response of the request * @return string The response of the request
*/ */
private static function getFopen() private static function getFopen()
@@ -218,4 +205,99 @@ class Response
return $content; return $content;
} }
/**
* Starts a HTTP request via cURL
*
* @return string The response of the request
*/
private static function getCurl()
{
$args = func_get_args();
$args = count($args) > 1 ? $args : array_shift($args);
$uri = $args[0];
$options = $args[1];
$callback = $args[2];
$ch = curl_init($uri);
$response = static::_curl_exec_follow($ch, $options, $callback);
if ($errno = curl_errno($ch)) {
$error_message = curl_strerror($errno);
throw new \RuntimeException("cURL error ({$errno}):\n {$error_message}");
}
curl_close($ch);
return $response;
}
private static function _curl_exec_follow($ch, $options, $callback)
{
if ($callback) {
curl_setopt_array(
$ch,
[
CURLOPT_NOPROGRESS => false,
CURLOPT_PROGRESSFUNCTION => ['self', 'progress']
]
);
}
// no open_basedir set, we can proceed normally
if (!ini_get('open_basedir')) {
curl_setopt_array($ch, $options['curl']);
return curl_exec($ch);
}
$max_redirects = isset($options['curl'][CURLOPT_MAXREDIRS]) ? $options['curl'][CURLOPT_MAXREDIRS] : 3;
$options['curl'][CURLOPT_FOLLOWLOCATION] = false;
// open_basedir set but no redirects to follow, we can disable followlocation and proceed normally
curl_setopt_array($ch, $options['curl']);
if ($max_redirects <= 0) {
return curl_exec($ch);
}
$uri = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
$rch = curl_copy_handle($ch);
curl_setopt($rch, CURLOPT_HEADER, true);
curl_setopt($rch, CURLOPT_NOBODY, true);
curl_setopt($rch, CURLOPT_FORBID_REUSE, false);
curl_setopt($rch, CURLOPT_RETURNTRANSFER, true);
do {
curl_setopt($rch, CURLOPT_URL, $uri);
$header = curl_exec($rch);
if (curl_errno($rch)) {
$code = 0;
} else {
$code = curl_getinfo($rch, CURLINFO_HTTP_CODE);
if ($code == 301 || $code == 302) {
preg_match('/Location:(.*?)\n/', $header, $matches);
$uri = trim(array_pop($matches));
} else {
$code = 0;
}
}
} while ($code && --$max_redirects);
curl_close($rch);
if (!$max_redirects) {
if ($max_redirects === null) {
trigger_error('Too many redirects. When following redirects, libcurl hit the maximum amount.', E_USER_WARNING);
}
return false;
}
curl_setopt($ch, CURLOPT_URL, $uri);
return curl_exec($ch);
}
} }

View File

@@ -1,22 +1,32 @@
<?php <?php
namespace Grav\Common\GPM; namespace Grav\Common\GPM;
use Grav\Common\Grav;
/**
* Class Upgrader
*
* @package Grav\Common\GPM
*/
class Upgrader class Upgrader
{ {
/** /**
* Remote details about latest Grav version * Remote details about latest Grav version
*
* @var Packages * @var Packages
*/ */
private $remote; private $remote;
/** /**
* Internal cache * Internal cache
*
* @var Iterator * @var Iterator
*/ */
protected $cache; protected $cache;
/** /**
* Creates a new GPM instance with Local and Remote packages available * Creates a new GPM instance with Local and Remote packages available
*
* @param boolean $refresh Applies to Remote Packages only and forces a refetch of data * @param boolean $refresh Applies to Remote Packages only and forces a refetch of data
* @param callable $callback Either a function or callback in array notation * @param callable $callback Either a function or callback in array notation
*/ */
@@ -27,6 +37,7 @@ class Upgrader
/** /**
* Returns the release date of the latest version of Grav * Returns the release date of the latest version of Grav
*
* @return string * @return string
*/ */
public function getReleaseDate() public function getReleaseDate()
@@ -36,6 +47,7 @@ class Upgrader
/** /**
* Returns the version of the installed Grav * Returns the version of the installed Grav
*
* @return string * @return string
*/ */
public function getLocalVersion() public function getLocalVersion()
@@ -45,6 +57,7 @@ class Upgrader
/** /**
* Returns the version of the remotely available Grav * Returns the version of the remotely available Grav
*
* @return string * @return string
*/ */
public function getRemoteVersion() public function getRemoteVersion()
@@ -54,6 +67,7 @@ class Upgrader
/** /**
* Returns an array of assets available to download remotely * Returns an array of assets available to download remotely
*
* @return array * @return array
*/ */
public function getAssets() public function getAssets()
@@ -63,6 +77,7 @@ class Upgrader
/** /**
* Returns the changelog list for each version of Grav * Returns the changelog list for each version of Grav
*
* @param string $diff the version number to start the diff from * @param string $diff the version number to start the diff from
* *
* @return array return the changelog list for each version * @return array return the changelog list for each version
@@ -72,8 +87,21 @@ class Upgrader
return $this->remote->getChangelog($diff); return $this->remote->getChangelog($diff);
} }
/**
* @return bool
*/
public function meetsRequirements()
{
if (version_compare(PHP_VERSION, GRAV_PHP_MIN, '<')) {
return false;
}
return true;
}
/** /**
* Checks if the currently installed Grav is upgradable to a newer version * Checks if the currently installed Grav is upgradable to a newer version
*
* @return boolean True if it's upgradable, False otherwise. * @return boolean True if it's upgradable, False otherwise.
*/ */
public function isUpgradable() public function isUpgradable()
@@ -83,6 +111,7 @@ class Upgrader
/** /**
* Checks if Grav is currently symbolically linked * Checks if Grav is currently symbolically linked
*
* @return boolean True if Grav is symlinked, False otherwise. * @return boolean True if Grav is symlinked, False otherwise.
*/ */

View File

@@ -57,8 +57,6 @@ class Grav extends Container
$container['grav'] = $container; $container['grav'] = $container;
$container['debugger'] = new Debugger(); $container['debugger'] = new Debugger();
$container['debugger']->startTimer('_init', 'Initialize'); $container['debugger']->startTimer('_init', 'Initialize');
@@ -114,7 +112,7 @@ class Grav extends Container
/** @var Uri $uri */ /** @var Uri $uri */
$uri = $c['uri']; $uri = $c['uri'];
$path = rtrim($uri->path(), '/'); $path = $uri->path(); // Don't trim to support trailing slash default routes
$path = $path ?: '/'; $path = $path ?: '/';
$page = $pages->dispatch($path); $page = $pages->dispatch($path);
@@ -185,8 +183,6 @@ class Grav extends Container
/** @var Debugger $debugger */ /** @var Debugger $debugger */
$debugger = $this['debugger']; $debugger = $this['debugger'];
// Initialize configuration. // Initialize configuration.
$debugger->startTimer('_config', 'Configuration'); $debugger->startTimer('_config', 'Configuration');
$this['config']->init(); $this['config']->init();
@@ -201,7 +197,10 @@ class Grav extends Container
// Use output buffering to prevent headers from being sent too early. // Use output buffering to prevent headers from being sent too early.
ob_start(); ob_start();
if ($this['config']->get('system.cache.gzip')) { if ($this['config']->get('system.cache.gzip')) {
ob_start('ob_gzhandler'); // Enable zip/deflate with a fallback in case of if browser does not support compressing.
if(!ob_start("ob_gzhandler")) {
ob_start();
}
} }
// Initialize the timezone // Initialize the timezone
@@ -227,7 +226,6 @@ class Grav extends Container
$debugger->startTimer('themes', 'Themes'); $debugger->startTimer('themes', 'Themes');
$this['themes']->init(); $this['themes']->init();
$this->fireEvent('onThemeInitialized');
$debugger->stopTimer('themes'); $debugger->stopTimer('themes');
$task = $this['task']; $task = $this['task'];
@@ -296,7 +294,10 @@ class Grav extends Container
if ($uri->isExternal($route)) { if ($uri->isExternal($route)) {
$url = $route; $url = $route;
} else { } else {
$url = rtrim($uri->rootUrl(), '/') .'/'. trim($route, '/'); if ($this['config']->get('system.pages.redirect_trailing_slash', true))
$url = rtrim($uri->rootUrl(), '/') .'/'. trim($route, '/'); // Remove trailing slash
else
$url = rtrim($uri->rootUrl(), '/') .'/'. ltrim($route, '/'); // Support trailing slash default routes
} }
header("Location: {$url}", true, $code); header("Location: {$url}", true, $code);
@@ -412,38 +413,49 @@ class Grav extends Container
*/ */
public function shutdown() public function shutdown()
{ {
if ($this['config']->get('system.debugger.shutdown.close_connection')) { // Prevent user abort allowing onShutdown event to run without interruptions.
//stop user abort if (function_exists('ignore_user_abort')) {
if (function_exists('ignore_user_abort')) { @ignore_user_abort(true);
@ignore_user_abort(true);
}
// close the session
if (isset($this['session'])) {
$this['session']->close();
}
// flush buffer if gzip buffer was started
if ($this['config']->get('system.cache.gzip')) {
ob_end_flush(); // gzhandler buffer
}
// get lengh and close the connection
header('Content-Length: ' . ob_get_length());
header("Connection: close");
// flush the regular buffer
ob_end_flush();
@ob_flush();
flush();
// fix for fastcgi close connection issue
if (function_exists('fastcgi_finish_request')) {
@fastcgi_finish_request();
}
} }
// Close the session allowing new requests to be handled.
if (isset($this['session'])) {
$this['session']->close();
}
if ($this['config']->get('system.debugger.shutdown.close_connection', true)) {
// Flush the response and close the connection to allow time consuming tasks to be performed without leaving
// the connection to the client open. This will make page loads to feel much faster.
// FastCGI allows us to flush all response data to the client and finish the request.
$success = function_exists('fastcgi_finish_request') ? @fastcgi_finish_request() : false;
if (!$success) {
// Unfortunately without FastCGI there is no way to close the connection. We need to ask browser to
// close the connection for us.
if ($this['config']->get('system.cache.gzip')) {
// Flush gzhandler buffer if gzip setting was enabled.
ob_end_flush();
} else {
// Without gzip we have no other choice than to prevent server from compressing the output.
// This action turns off mod_deflate which would prevent us from closing the connection.
header('Content-Encoding: none');
}
// Get length and close the connection.
header('Content-Length: ' . ob_get_length());
header("Connection: close");
// Finally flush the regular buffer.
ob_end_flush();
@ob_flush();
flush();
}
}
// Run any time consuming tasks.
$this->fireEvent('onShutdown'); $this->fireEvent('onShutdown');
} }
@@ -457,12 +469,26 @@ class Grav extends Container
/** @var Uri $uri */ /** @var Uri $uri */
$uri = $this['uri']; $uri = $this['uri'];
/** @var Config $config */
$config = $this['config'];
$uri_extension = $uri->extension();
$fallback_types = $config->get('system.media.allowed_fallback_types', null);
$supported_types = $config->get('media');
// Check whitelist first, then ensure extension is a valid media type
if (!empty($fallback_types) && !in_array($uri_extension, $fallback_types)) {
return;
} elseif (!array_key_exists($uri_extension, $supported_types)) {
return;
}
$path_parts = pathinfo($path); $path_parts = pathinfo($path);
$page = $this['pages']->dispatch($path_parts['dirname'], true); $page = $this['pages']->dispatch($path_parts['dirname'], true);
if ($page) { if ($page) {
$media = $page->media()->all(); $media = $page->media()->all();
$parsed_url = parse_url(urldecode($uri->basename())); $parsed_url = parse_url(rawurldecode($uri->basename()));
$media_file = $parsed_url['path']; $media_file = $parsed_url['path'];
@@ -478,7 +504,6 @@ class Grav extends Container
} }
// unsupported media type, try to download it... // unsupported media type, try to download it...
$uri_extension = $uri->extension();
if ($uri_extension) { if ($uri_extension) {
$extension = $uri_extension; $extension = $uri_extension;
} else { } else {
@@ -491,7 +516,7 @@ class Grav extends Container
if ($extension) { if ($extension) {
$download = true; $download = true;
if (in_array(ltrim($extension, '.'), $this['config']->get('system.media.unsupported_inline_types', []))) { if (in_array(ltrim($extension, '.'), $config->get('system.media.unsupported_inline_types', []))) {
$download = false; $download = false;
} }
Utils::download($page->path() . DIRECTORY_SEPARATOR . $uri->basename(), $download); Utils::download($page->path() . DIRECTORY_SEPARATOR . $uri->basename(), $download);

View File

@@ -131,7 +131,7 @@ class Truncator {
$inner .= $txt; $inner .= $txt;
if ($remaining < 0) { if ($remaining < 0) {
if (static::ellipsable($node)) { if (static::ellipsable($node)) {
$inner = preg_replace('/(?:[\s\pP]+|(?:&(?:[a-z]+|#[0-9]+);?))*$/', '', $inner).$opts['ellipsis']; $inner = preg_replace('/(?:[\s\pP]+|(?:&(?:[a-z]+|#[0-9]+);?))*$/u', '', $inner).$opts['ellipsis'];
$opts['ellipsis'] = ''; $opts['ellipsis'] = '';
$opts['was_truncated'] = true; $opts['was_truncated'] = true;
} }

View File

@@ -215,4 +215,26 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
return $this; 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);
}
} }

View File

@@ -162,7 +162,7 @@ class Language
*/ */
public function setActiveFromUri($uri) public function setActiveFromUri($uri)
{ {
$regex = '/(^\/(' . $this->getAvailable() . ')).*/'; $regex = '/(^\/(' . $this->getAvailable() . '))(?:\/.*|$)/i';
// if languages set // if languages set
if ($this->enabled()) { if ($this->enabled()) {
@@ -352,7 +352,7 @@ class Language
if ($this->config->get('system.languages.translations_fallback', true)) { if ($this->config->get('system.languages.translations_fallback', true)) {
$languages = $this->getFallbackLanguages(); $languages = $this->getFallbackLanguages();
} else { } else {
$languages = (array)$this->getDefault(); $languages = (array)$this->getLanguage();
} }
} }
} else { } else {

View File

@@ -193,7 +193,7 @@ class LanguageCodes
], ],
"fr" => [ "fr" => [
"name" => "French", "name" => "French",
"nativeName" => "français" "nativeName" => "Français"
], ],
"ff" => [ "ff" => [
"name" => "Fula", "name" => "Fula",

View File

@@ -1,12 +1,9 @@
<?php <?php
namespace Grav\Common\Markdown; namespace Grav\Common\Markdown;
use Grav\Common\Config\Config;
use Grav\Common\Debugger;
use Grav\Common\GravTrait; use Grav\Common\GravTrait;
use Grav\Common\Page\Medium\Medium;
use Grav\Common\Uri; use Grav\Common\Uri;
use Grav\Common\Utils; use RocketTheme\Toolbox\Event\Event;
/** /**
* A trait to add some custom processing to the identifyLink() method in Parsedown and ParsedownExtra * A trait to add some custom processing to the identifyLink() method in Parsedown and ParsedownExtra
@@ -19,9 +16,11 @@ trait ParsedownGravTrait
protected $base_url; protected $base_url;
protected $pages_dir; protected $pages_dir;
protected $special_chars; protected $special_chars;
protected $twig_link_regex = '/\!*\[(?:.*)\]\((\{([\{%#])\s*(.*?)\s*(?:\2|\})\})\)/'; protected $twig_link_regex = '/\!*\[(?:.*)\]\((\{([\{%#])\s*(.*?)\s*(?:\2|\})\})\)/';
public $completable_blocks = [];
public $continuable_blocks = [];
/** /**
* Initialization function to setup key variables needed by the MarkdownGravLinkTrait * Initialization function to setup key variables needed by the MarkdownGravLinkTrait
* *
@@ -30,8 +29,10 @@ trait ParsedownGravTrait
*/ */
protected function init($page, $defaults) protected function init($page, $defaults)
{ {
$grav = self::getGrav();
$this->page = $page; $this->page = $page;
$this->pages = self::getGrav()['pages']; $this->pages = $grav['pages'];
$this->BlockTypes['{'] [] = "TwigTag"; $this->BlockTypes['{'] [] = "TwigTag";
$this->base_url = rtrim(self::getGrav()['base_url'] . self::getGrav()['pages']->base(), '/'); $this->base_url = rtrim(self::getGrav()['base_url'] . self::getGrav()['pages']->base(), '/');
$this->pages_dir = self::getGrav()['locator']->findResource('page://'); $this->pages_dir = self::getGrav()['locator']->findResource('page://');
@@ -45,8 +46,67 @@ trait ParsedownGravTrait
$this->setUrlsLinked($defaults['auto_url_links']); $this->setUrlsLinked($defaults['auto_url_links']);
$this->setMarkupEscaped($defaults['escape_markup']); $this->setMarkupEscaped($defaults['escape_markup']);
$this->setSpecialChars($defaults['special_chars']); $this->setSpecialChars($defaults['special_chars']);
$grav->fireEvent('onMarkdownInitialized', new Event(['markdown' => $this]));
} }
/**
* Be able to define a new Block type or override an existing one
*
* @param $type
* @param $tag
*/
public function addBlockType($type, $tag, $continuable = false, $completable = false)
{
$this->BlockTypes[$type] []= $tag;
if ($continuable) {
$this->continuable_blocks[] = $tag;
}
if ($completable) {
$this->completable_blocks[] = $tag;
}
}
/**
* Be able to define a new Inline type or override an existing one
*
* @param $type
* @param $tag
*/
public function addInlineType($type, $tag)
{
$this->InlineTypes[$type] []= $tag;
$this->inlineMarkerList .= $type;
}
/**
* Overrides the default behavior to allow for plugin-provided blocks to be continuable
*
* @param $Type
* @return bool
*/
protected function isBlockContinuable($Type)
{
$continuable = in_array($Type, $this->continuable_blocks) || method_exists($this, 'block'.$Type.'Continue');
return $continuable;
}
/**
* Overrides the default behavior to allow for plugin-provided blocks to be completable
*
* @param $Type
* @return bool
*/
protected function isBlockCompletable($Type)
{
$completable = in_array($Type, $this->completable_blocks) || method_exists($this, 'block'.$Type.'Complete');
return $completable;
}
/** /**
* Make the element function publicly accessible, Medium uses this to render from Twig * Make the element function publicly accessible, Medium uses this to render from Twig
* *
@@ -77,7 +137,7 @@ trait ParsedownGravTrait
*/ */
protected function blockTwigTag($Line) protected function blockTwigTag($Line)
{ {
if (preg_match('/[{%|{{|{#].*[#}|}}|%}]/', $Line['body'], $matches)) { if (preg_match('/(?:{{|{%|{#)(.*)(?:}}|%}|#})/', $Line['body'], $matches)) {
$Block = array( $Block = array(
'markup' => $Line['body'], 'markup' => $Line['body'],
); );
@@ -149,9 +209,9 @@ trait ParsedownGravTrait
} }
// if there is a media file that matches the path referenced.. // if there is a media file that matches the path referenced..
if ($media && isset($media->all()[$url['path']])) { if ($media && isset($media->all()[$path_parts['basename']])) {
// get the medium object // get the medium object
$medium = $media->all()[$url['path']]; $medium = $media->all()[$path_parts['basename']];
// if there is a query, then parse it and build action calls // if there is a query, then parse it and build action calls
if (isset($url['query'])) { if (isset($url['query'])) {
@@ -208,13 +268,64 @@ trait ParsedownGravTrait
if (isset($excerpt['element']['attributes']['href'])) { if (isset($excerpt['element']['attributes']['href'])) {
$url = parse_url(htmlspecialchars_decode($excerpt['element']['attributes']['href'])); $url = parse_url(htmlspecialchars_decode($excerpt['element']['attributes']['href']));
// if there is no scheme, the file is local // 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] : true;
$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] = str_replace(',', ' ', $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 and we'll need to convert that URL
if (!isset($url['scheme']) && (count($url) > 0)) { if (!isset($url['scheme']) && (count($url) > 0)) {
// convert the URl is required $excerpt['element']['attributes']['href'] = Uri::convertUrl($this->page, Uri::buildUrl($url), $type, true);
$excerpt['element']['attributes']['href'] = Uri::convertUrl($this->page, Uri::buildUrl($url), $type); } else {
$excerpt['element']['attributes']['href'] = Uri::buildUrl($url);
} }
} }
return $excerpt; return $excerpt;
} }
// For extending this class via plugins
public function __call($method, $args)
{
if (isset($this->$method) === true) {
$func = $this->$method;
return call_user_func_array($func, $args);
}
}
} }

Some files were not shown because too many files have changed in this diff Show More