Merge branch 'release/1.0.9'

This commit is contained in:
Andy Miller
2016-02-05 16:00:22 -07:00
161 changed files with 8126 additions and 1544 deletions

5
.gitignore vendored
View File

@@ -36,3 +36,8 @@ Thumbs.db
# phpstorm
.idea/*
user/config/security.yaml
tests/_output/*
tests/_support/_generated/*
tests/cache/*
tests/error.log

View File

@@ -44,7 +44,7 @@ RewriteRule .* index.php [L]
## Begin - Security
# Block all direct access for these folders
RewriteRule ^(.git|cache|bin|logs|backup|webserver-configs)/(.*) error [F]
RewriteRule ^(.git|cache|bin|logs|backup|webserver-configs|tests)/(.*) error [F]
# Block access to specific file types for these system folders
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
@@ -52,7 +52,7 @@ RewriteRule ^(user)/(.*)\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ error [F]
# Block all direct access to .md files:
RewriteRule \.md$ error [F]
# Block all direct access to files and folders beginning with a dot
RewriteRule (^\.|/\.) - [F]
RewriteRule (^|/)\.(?!well-known) - [F]
# Block access to specific files in the root folder
RewriteRule ^(LICENSE.txt|composer.lock|composer.json|\.htaccess)$ error [F]
## End - Security

View File

@@ -1,7 +1,12 @@
language: php
php: 5.6
php:
- '5.5'
- '5.6'
- '7.0'
- hhvm
branches:
only:
- develop
- master
- build_test
notifications:
@@ -13,8 +18,10 @@ notifications:
rooms:
- secure: "bqO0wM1B7bJnQw2fuhquSXEqI9gw6WmFytIh9sEWXzbYTzTUP5t0PcKOd3FT2BNMRaDxPJLVl+vG/oqmqDUBkEmOGcG504IQjeNzZqnMz0tXQMIcCc22Las9tFfc4Jf6RVi/qGomFtHGE9Wgii+TAN4zqZaufbNjwd8SyjO0+W8="
template:
- '%{repository}#%{build_number} (%{branch}): Grav Core and Skeletons packages have been uploaded. (<a href="%{build_url}">Details</a>)'
- '%{repository}#%{build_number} (%{branch}): Travis Job Finished [%{duration}] (<a href="%{build_url}">Details</a>)'
format: html
slack:
secure: dowksPsxxCxGKT6nis5hUgkp6+ZDAhoqzQHF9rJnx4hx0iEygPhVBs7pKl9yL2jubYJoLs+EXwE7z1dYgDAEJh4BnfrCokCMLpFGcxVxQC/HeAUdSQ2/RtdBYR5PRT75ScaFpqM/SfXXZVtnwVXAw9Z+JC6BjQ9vmn23m51Jw4k=
env:
global:
# Colors!
@@ -36,21 +43,31 @@ env:
- secure: "einUtSEkUWy2IrqLXyVjwUU+mwaaoiOXRRVdLBpA3Zye6bZx8cm5h/5AplkPWhM/NmCJoW/MwNZHHkFhlr3mDRov5iOxVmTTYfnXB+I5lxYTSgduOLLErS7mU8hfADpVDU8bHNU44fNGD3UEiG1PD4qQBX4DMlqIFmR20mjs81k="
# GH_API_USER [for curl]
- secure: "Xbk/V9aIys0NxccJGR3Zrm2GRxDnA0RuazBs1puIboTYDhbi0Z7JTL+mOx3xp5Kfoniad/xAuijQESTM9MMrKqq/qCzhAMaC1+vcL4pCHZH4NSG6DBxB9BPkKVFq+1llu5FTEf8bkxHzwGR0l1ARW6TVRcgTHr5B58bCEIwEOrI="
# Latest Release version
- 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:
- export TZ=Pacific/Honolulu
- composer self-update
- 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;
- if [ ! -z "$TRAVIS_TAG" ]; then
cd "${RT_DEVTOOLS}";
./build-grav.sh skeletons.txt;
- if [ $TRAVIS_BRANCH == 'develop' ] || [ $TRAVIS_PULL_REQUEST != 'false' ]; then
composer install --dev --prefer-dist;
fi
- if [ $TRAVIS_BRANCH != 'develop' ] && [ $TRAVIS_PHP_VERSION == '5.6' ] && [ $TRAVIS_PULL_REQUEST == "false" ]; then
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);
go get github.com/aktau/github-release;
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
cd ${RT_DEVTOOLS};
./build-grav.sh skeletons.txt;
fi;
fi
before_script:
- if [ $TRAVIS_PHP_VERSION != 'hhvm' ]; then phpenv config-rm xdebug.ini; fi
script:
- if [ ! -z "$TRAVIS_TAG" ]; then
- if [ $TRAVIS_BRANCH == 'develop' ] || [ $TRAVIS_PULL_REQUEST != 'false' ]; then
vendor/bin/codecept run;
else
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);
fi
- if [ ! -z "$TRAVIS_TAG" ] && [ $TRAVIS_BRANCH != 'develop' ] && [ $TRAVIS_PHP_VERSION == '5.6' ] && [ $TRAVIS_PULL_REQUEST == "false" ]; then
FILES="$RT_DEVTOOLS/grav-dist/*.zip";
for file in ${FILES[@]}; do
NAME=${file##*/};

View File

@@ -1,10 +1,54 @@
# v1.0.9
## 02/05/2016
1. [](#new)
* New **Unit Testing** via Codeception http://codeception.com/
* New **page-level SSL** functionality when using `absolute_urls`
* Added `reverse_proxy` config option for issues with non-standard ports
* Added `proxy_url` config option to support GPM behind proxy servers #639
* New `Pages::parentsRawRoutes()` method
* Enhanced `bin/gpm info` CLI command with Changelog support #559
* Ability to add empty *Folder* via admin plugin
* Added latest `jQuery 2.2.0` library to core
* Added translations from Crowdin
1. [](#improved)
* [BC] Metadata now supports only flat arrays. To use open graph metas and the likes (ie, 'og:title'), simply specify it in the key.
* Refactored `Uri::convertUrl()` method to be more reliable + tests created
* Date for last update of a modular sub-page sets modified date of modular page itself
* Split configuration up into two steps
* Moved Grav-based `base_uri` variables into `Uri::init()`
* Refactored init in `URI` to better support testing
* Allow `twig_vars` to be exposed earlier and merged later
* Avoid setting empty metadata
* Accept single group access as a string rather than requiring an array
* Return `$this` in Page constructor and init to allow chaining
* Added `ext-*` PHP requirements to `composer.json`
* Use Whoops 2.0 library while supporting old style
* Removed redundant old default-hash fallback mechanisms
* Commented out default redirects and routes in `site.yaml`
* Added `/tests` folder to deny's of all `webserver-configs/*` files
* Various PS and code style fixes
1. [](#bugfix)
* Fix default generator metadata
* Fix for broken image processing caused by `Uri::convertUrl()` bugs
* Fix loading JS and CSS from collections #623
* Fix stream overriding
* Remove the URL extension for home link
* Fix permissions when the user has no access level set at all
* Fix issue with user with multiple groups getting denied on first group
* Fixed an issue with `Pages()` internal cache lookup not being unique enough
* Fix for bug with `site.redirects` and `site.routes` being an empty list
* [Markdown] Don't process links for **special protocols**
* [Whoops] serve JSON errors when request is JSON
# 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
* Removed IP from Nonce generation. Should be more reliable in a variety of scenarios
# v1.0.7
## 01/07/2016
@@ -18,13 +62,13 @@
* 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)
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
* 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
@@ -34,7 +78,7 @@
* 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 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:`

View File

@@ -1,4 +1,4 @@
# ![](https://avatars1.githubusercontent.com/u/8237355?v=2&s=50) Grav
# ![](https://avatars1.githubusercontent.com/u/8237355?v=2&s=50) Grav [![Build Status](https://travis-ci.org/getgrav/grav.svg?branch=develop)](https://travis-ci.org/getgrav/grav)
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/cfd20465-d0f8-4a0a-8444-467f5b5f16ad/mini.png)](https://insight.sensiolabs.com/projects/cfd20465-d0f8-4a0a-8444-467f5b5f16ad) [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/getgrav/grav?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -100,11 +100,11 @@ What you mainly want to know is that:
* [What is Grav?](http://learn.getgrav.org/basics/what-is-grav)
* [Install](http://learn.getgrav.org/basics/installation) Grav in few seconds
* Understand the [Configuration](http://learn.getgrav.org/basics/grav-configuration)
* Take a peek at our available free [Skeletons](http://getgrav.org/downloads/skeletons#extras)
* If you have questions, check out `#grav` on irc.freenode.net
* Take a peek at our available free [Skeletons](http://getgrav.org/downloads/skeletons)
* If you have questions, jump on our [Gitter Room](https://gitter.im/getgrav/grav)!
* Have fun!
# Exploring more
# Exploring More
* Have a look at our [Basic Tutorial](http://learn.getgrav.org/basics/basic-tutorial)
* Dive into more [advanced](http://learn.getgrav.org/advanced) functions
@@ -116,3 +116,10 @@ See [LICENSE](LICENSE.txt)
[gitflow-model]: http://nvie.com/posts/a-successful-git-branching-model/
[gitflow-extensions]: https://github.com/nvie/gitflow
# Running Tests
First install the dev dependencies by running `composer update` from the Grav root.
Then `composer test` will run the Unit Tests, which should be always executed successfully on any site.
You can also run a single unit test file, e.g. `composer test tests/unit/Grav/Common/AssetsTest.php`

View File

@@ -39,6 +39,7 @@ if (!function_exists('curl_version')) {
$grav = Grav::instance(array('loader' => $autoload));
$grav['config']->init();
$grav['uri']->init();
$grav['streams'];
$app = new Application('Grav Package Manager', GRAV_VERSION);
@@ -51,4 +52,6 @@ $app->addCommands(array(
new \Grav\Console\Gpm\UpdateCommand(),
new \Grav\Console\Gpm\SelfupgradeCommand(),
));
$app->setDefaultCommand('index');
$app->run();

View File

@@ -107,10 +107,12 @@ try {
exit;
}
foreach ($commands as $command) {
require_once "plugins://{$name}/cli/{$command}";
$command = 'Grav\Plugin\Console\\' . preg_replace('/.php$/', '', $command);
$app->add(new $command());
foreach ($commands as $command_path) {
require_once "plugins://{$name}/cli/{$command_path}";
$command_class = 'Grav\Plugin\Console\\' . preg_replace('/.php$/', '', $command_path);
$command = new $command_class();
$app->add($command);
}
$app->run($input);

16
codeception.yml Normal file
View File

@@ -0,0 +1,16 @@
actor: Tester
paths:
tests: tests
log: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs
settings:
bootstrap: _bootstrap.php
colors: true
memory_limit: 1024M
extensions:
enabled:
- Codeception\Extension\RunFailed
modules:
config:

View File

@@ -7,7 +7,8 @@
"license": "MIT",
"require": {
"php": ">=5.5.9",
"twig/twig": "~1.23",
"twig/twig": "~1.24",
"erusev/parsedown": "dev-master as 1.6.0",
"erusev/parsedown-extra": "~0.7",
"symfony/yaml": "~2.8",
"symfony/console": "~2.8",
@@ -15,22 +16,22 @@
"symfony/var-dumper": "~2.8",
"symfony/polyfill-iconv": "~1.0",
"doctrine/cache": "~1.5",
"filp/whoops": "2.0.0-alpha2",
"filp/whoops": "~2.0",
"monolog/monolog": "~1.0",
"gregwar/image": "~2.0",
"ircmaxell/password-compat": "1.0.*",
"mrclay/minify": "~2.2",
"donatj/phpuseragentparser": "~0.3",
"pimple/pimple": "~3.0",
"rockettheme/toolbox": "~1.2",
"maximebf/debugbar": "~1.10"
"maximebf/debugbar": "~1.10",
"ext-mbstring": "*",
"ext-openssl": "*",
"ext-curl": "*"
},
"require-dev": {
"codeception/codeception": "^2.1",
"fzaninotto/faker": "^1.5"
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/getgrav/parsedown"
}
],
"autoload": {
"psr-4": {
"Grav\\": "system/src/Grav"
@@ -41,7 +42,9 @@
"exclude": ["VERSION"]
},
"scripts": {
"post-create-project-cmd": "bin/grav install"
"post-create-project-cmd": "bin/grav install",
"test": "vendor/bin/codecept run unit",
"test-windows": "vendor\\bin\\codecept run unit"
},
"extra": {
"branch-alias": {

1645
composer.lock generated

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -848,6 +848,24 @@ form:
underline: true
fields:
proxy_url:
type: text
size: medium
placeholder: "e.g. 127.0.0.1:3128"
label: PLUGIN_ADMIN.PROXY_URL
help: PLUGIN_ADMIN.PROXY_URL_HELP
reverse_proxy_setup:
type: toggle
label: PLUGIN_ADMIN.REVERSE_PROXY
highlight: 0
help: PLUGIN_ADMIN.REVERSE_PROXY_HELP
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
wrapped_site:
type: toggle
label: PLUGIN_ADMIN.WRAPPED_SITE

View File

@@ -139,7 +139,7 @@ form:
type: select
label: PLUGIN_ADMIN.PARENT
classes: fancy
'@data-options': '\Grav\Common\Page\Pages::parents'
'@data-options': '\Grav\Common\Page\Pages::parentsRawRoutes'
'@data-default': '\Grav\Plugin\admin::route'
options:
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT

View File

@@ -0,0 +1,35 @@
rules:
slug:
pattern: "[a-z][a-z0-9_\-]+"
min: 2
max: 80
form:
validation: loose
fields:
section:
type: section
title: PLUGIN_ADMIN.ADD_PAGE
folder:
type: text
label: PLUGIN_ADMIN.FOLDER_NAME
help: PLUGIN_ADMIN.FOLDER_NAME_HELP
validate:
type: slug
required: true
route:
type: select
label: PLUGIN_ADMIN.PARENT_PAGE
classes: fancy
'@data-options': '\Grav\Common\Page\Pages::parents'
'@data-default': '\Grav\Plugin\admin::getLastPageRoute'
options:
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
validate:
required: true
blueprint:
type: blueprint

View File

@@ -41,4 +41,4 @@ form:
label: PLUGIN_ADMIN.SITE_ACCESS
multiple: false
validate:
type: array
type: array

View File

@@ -16,12 +16,12 @@ summary:
delimiter: === # The summary delimiter
redirects:
/redirect-test: / # Redirect test goes to home page
/old/(.*): /new/$1 # Would redirect /old/my-page to /new/my-page
# /redirect-test: / # Redirect test goes to home page
# /old/(.*): /new/$1 # Would redirect /old/my-page to /new/my-page
routes:
/something/else: '/blog/sample-3' # Alias for /blog/sample-3
/new/(.*): '/blog/$1' # Regex any /new/my-page URL to /blog/my-page Route
# /something/else: '/blog/sample-3' # Alias for /blog/sample-3
# /new/(.*): '/blog/$1' # Regex any /new/my-page URL to /blog/my-page Route
blog:
route: '/blog' # Custom value added (accessible via system.blog.route)

View File

@@ -3,6 +3,8 @@ timezone: '' # Valid values: http://php.net/manua
default_locale: # Default locale (defaults to system)
param_sep: ':' # Parameter separator, use ';' for Apache on windows
wrapped_site: false # For themes/plugins to know if Grav is wrapped by another platform
reverse_proxy_setup: false # Running in a reverse proxy scenario with different webserver ports than proxy
proxy_url: # Configure a manual proxy URL for GPM (eg 127.0.0.1:3128)
languages:
supported: [] # List of languages supported. eg: [en, fr, de]
@@ -85,7 +87,7 @@ assets: # Configuration for Assets Manager (
js_minify: true # Minify the JS during pipelining
enable_asset_timestamp: false # Enable asset timestamps
collections:
jquery: system://assets/jquery/jquery-2.1.4.min.js
jquery: system://assets/jquery/jquery-2.x.min.js
errors:
display: false # Display full backtrace-style error page
@@ -113,4 +115,4 @@ session:
timeout: 1800 # Timeout in seconds
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
httponly: true # Set session HTTP only. If true, indicates that cookies should be used only over HTTP, and JavaScript modification is not allowed.
httponly: true # Set session HTTP only. If true, indicates that cookies should be used only over HTTP, and JavaScript modification is not allowed.

View File

@@ -2,7 +2,7 @@
// Some standard defines
define('GRAV', true);
define('GRAV_VERSION', '1.0.8');
define('GRAV_VERSION', '1.0.9');
define('DS', '/');
define('GRAV_PHP_MIN', '5.5.9');

View File

@@ -1,39 +1,80 @@
---
INFLECTOR_UNCOUNTABLE:
- vybavení
- informace
- rýže
- peníze
- druhy
- série
- ryba
- ovce
INFLECTOR_IRREGULAR:
person: lidé
man: muži
child: děti
sex: pohlaví
move: pohyby
INFLECTOR_ORDINALS:
default: '.'
first: '.'
second: '.'
third: '.'
NICETIME:
NO_DATE_PROVIDED: Datum nebylo vloženo
BAD_DATE: Chybné datum
AGO: zpět
FROM_NOW: od teď
SECOND: sekunda
MINUTE: minuta
HOUR: hodina
DAY: den
WEEK: týden
MONTH: měsíc
YEAR: rok
DECADE: dekáda
SEC: sek
MIN: min
HR: hod
DAY: den
WK: t
MO: m
YR: r
DEC: dek
SECOND_PLURAL: sekundy
MINUTE_PLURAL: minuty
HOUR_PLURAL: hodiny
DAY_PLURAL: dny
WEEK_PLURAL: týdny
MONTH_PLURAL: měsíce
YEAR_PLURAL: roky
DECADE_PLURAL: dekády
SEC_PLURAL: sek
MIN_PLURAL: min
HR_PLURAL: hod
DAY_PLURAL: dny
WK_PLURAL: t
MO_PLURAL: m
YR_PLURAL: r
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']
NO_DATE_PROVIDED: Datum nebylo vloženo
BAD_DATE: Chybné datum
AGO: zpět
FROM_NOW: od teď
SECOND: sekunda
MINUTE: minuta
HOUR: hodina
DAY: den
WEEK: týden
MONTH: měsíc
YEAR: rok
DECADE: dekáda
SEC: sek
MIN: min
HR: hod
WK: t
MO: m
YR: r
DEC: dek
SECOND_PLURAL: sekundy
MINUTE_PLURAL: minuty
HOUR_PLURAL: hodiny
DAY_PLURAL: dny
WEEK_PLURAL: dny
MONTH_PLURAL: měsíce
YEAR_PLURAL: roky
DECADE_PLURAL: dekády
SEC_PLURAL: sek
MIN_PLURAL: min
HR_PLURAL: hod
WK_PLURAL: t
MO_PLURAL: m
YR_PLURAL: r
DEC_PLURAL: dek
FORM:
VALIDATION_FAIL: '<b>Ověření se nezdařilo:</b>'
MISSING_REQUIRED_FIELD: 'Chybí požadované pole:'
MONTHS_OF_THE_YEAR:
- ledna
- února
- března
- dubna
- května
- června
- července
- srpna
- září
- října
- listopadu
- prosince
DAYS_OF_THE_WEEK:
- Pondělí
- Úterý
- Středa
- Čtvrtek
- Pátek
- Sobota
- Neděle

View File

@@ -1,45 +1,83 @@
---
FRONTMATTER_ERROR_PAGE: |
---
title: %1$s
---
# Fehler: Frontmatter enthält Fehler
Pfad: `%2$s`
**%3$s **
```
%4$s
```
INFLECTOR_UNCOUNTABLE:
1: Informationen
2: Reis
3: Geld
INFLECTOR_IRREGULAR:
'person': 'Personen'
'man': 'Menschen'
'child': 'Kinder'
'sex': 'Geschlecht'
'move': 'Züge'
person: Personen
man: Menschen
child: Kinder
sex: Geschlecht
move: Züge
NICETIME:
NO_DATE_PROVIDED: Keine Daten vorhanden
BAD_DATE: Falsches Datum
AGO: her
FROM_NOW: ab jetzt
SECOND: Sekunde
MINUTE: Minute
HOUR: Stunde
DAY: Tag
WEEK: Woche
MONTH: Monat
YEAR: Jahr
DECADE: Dekade
SEC: sek
MIN: min
HR: std
DAY: Tag
WK: wo
MO: mo
YR: yh
DEC: dec
SECOND_PLURAL: Sekunden
MINUTE_PLURAL: Minuten
HOUR_PLURAL: Stunden
DAY_PLURAL: Tage
WEEK_PLURAL: Wochen
MONTH_PLURAL: Monate
YEAR_PLURAL: Jahre
DECADE_PLURAL: Dekaden
SEC_PLURAL: Sekunden
MIN_PLURAL: Minuten
HR_PLURAL: Stunden
DAY_PLURAL: Tage
WK_PLURAL: Wochen
MO_PLURAL: Monate
YR_PLURAL: Jahre
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']
NO_DATE_PROVIDED: Keine Daten vorhanden
BAD_DATE: Falsches Datum
AGO: her
FROM_NOW: ab jetzt
SECOND: Sekunde
MINUTE: Minute
HOUR: Stunde
DAY: Tag
WEEK: Woche
MONTH: Monat
YEAR: Jahr
DECADE: Dekade
SEC: sek
MIN: Min
HR: std
WK: wo
YR: yh
DEC: Jz
SECOND_PLURAL: Sekunden
MINUTE_PLURAL: Minuten
HOUR_PLURAL: Stunden
DAY_PLURAL: Tage
WEEK_PLURAL: Wochen
MONTH_PLURAL: Monate
YEAR_PLURAL: Jahre
DECADE_PLURAL: Dekaden
SEC_PLURAL: Sekunden
MIN_PLURAL: Minuten
HR_PLURAL: Stunden
WK_PLURAL: Wochen
MO_PLURAL: Monate
YR_PLURAL: Jahre
DEC_PLURAL: Dekaden
FORM:
VALIDATION_FAIL: '<b>Überprüfung fehlgeschlagen:</b>'
INVALID_INPUT: Ungültige Eingabe in
MISSING_REQUIRED_FIELD: 'Erforderliches Feld fehlt:'
MONTHS_OF_THE_YEAR:
- Januar
- Februar
- März
- April
- Mai
- Juni
- Juli
- August
- Semptember
- Oktober
- November
- Dezember
DAYS_OF_THE_WEEK:
- Montag
- Dienstag
- Mittwoch
- Donnerstag
- Freitag
- Samstag
- Sonntag

View File

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

View File

@@ -1,44 +1,76 @@
---
INFLECTOR_UNCOUNTABLE:
0: equipo
1: información
3: dinero
5: series
6: pescado
7: oveja
INFLECTOR_IRREGULAR:
man: hombres
child: niños
sex: sexos
INFLECTOR_ORDINALS:
first: ro
second: do
third: ro
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: 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
NO_DATE_PROVIDED: No se proporcionó fecha
BAD_DATE: Fecha erronea
AGO: antes
FROM_NOW: desde ahora
SECOND: segundo
MINUTE: minuto
HOUR: hora
DAY: día
WEEK: semana
MONTH: mes
YEAR: año
DECADE: década
SEC: seg
MIN: min
HR: h
WK: sem
MO: mes
YR: año
DEC: dec
SECOND_PLURAL: segundos
MINUTE_PLURAL: minutos
HOUR_PLURAL: horas
DAY_PLURAL: as
WEEK_PLURAL: semanas
MONTH_PLURAL: meses
YEAR_PLURAL: años
DECADE_PLURAL: décadas
SEC_PLURAL: segs
MIN_PLURAL: mins
HR_PLURAL: hs
WK_PLURAL: sem
MO_PLURAL: mes
YR_PLURAL: años
DEC_PLURAL: décadas
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']
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
- Agosto
- Septiembre
- Octubre
- Noviembre
- Diciembre
DAYS_OF_THE_WEEK:
- Lunes
- Martes
- Miércoles
- Jueves
- Viernes
- Sábado
- Domingo

View File

@@ -1,2 +1 @@
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,100 +1,138 @@
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```"
---
FRONTMATTER_ERROR_PAGE: |
---
title: %1$s
---
# Erreur : Frontmatter invalide
Path: `%2$s`
**%3$s**
```
%4$s
```
INFLECTOR_PLURALS:
'/(quiz)$/i': '\1zes'
'/^(ox)$/i': '\1en'
'/([m|l])ouse$/i': '\1ice'
'/(matr|vert|ind)ix|ex$/i': '\1ices'
'/(x|ch|ss|sh)$/i': '\1es'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([^aeiouy]|qu)y$/i': '\1ies'
'/(hive)$/i': '\1s'
'/(?:([^f])fe|([lr])f)$/i': '\1\2ves'
'/sis$/i': 'ses'
'/([ti])um$/i': '\1a'
'/(buffal|tomat)o$/i': '\1oes'
'/(bu)s$/i': '\1ses'
'/(alias|status)/i': '\1es'
'/(octop|vir)us$/i': '\1i'
'/(ax|test)is$/i': '\1es'
'/s$/i': 's'
'/$/': 's'
/(quiz)$/i: '\1zes'
/^(ox)$/i: '\1en'
"/([m|l])ouse$/i": '\1ice'
/(matr|vert|ind)ix|ex$/i: '\1ices'
/(x|ch|ss|sh)$/i: '\1es'
"/([^aeiouy]|qu)ies$/i": '\1y'
"/([^aeiouy]|qu)y$/i": '\1ies'
/(hive)$/i: '\1s'
"/(?:([^f])fe|([lr])f)$/i": '\1\2ves'
/sis$/i: ses
"/([ti])um$/i": '\1a'
/(buffal|tomat)o$/i: '\1oes'
/(bu)s$/i: '\1ses'
/(alias|status)/i: '\1es'
/(octop|vir)us$/i: '\1i'
/(ax|test)is$/i: '\1es'
/s$/i: s
/$/: s
INFLECTOR_SINGULAR:
'/(quiz)zes$/i': '\1'
'/(matr)ices$/i': '\1ix'
'/(vert|ind)ices$/i': '\1ex'
'/^(ox)en/i': '\1'
'/(alias|status)es$/i': '\1'
'/([octop|vir])i$/i': '\1us'
'/(cris|ax|test)es$/i': '\1is'
'/(shoe)s$/i': '\1'
'/(o)es$/i': '\1'
'/(bus)es$/i': '\1'
'/([m|l])ice$/i': '\1ouse'
'/(x|ch|ss|sh)es$/i': '\1'
'/(m)ovies$/i': '\1ovie'
'/(s)eries$/i': '\1eries'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([lr])ves$/i': '\1f'
'/(tive)s$/i': '\1'
'/(hive)s$/i': '\1'
'/([^f])ves$/i': '\1fe'
'/(^analy)ses$/i': '\1sis'
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
'/([ti])a$/i': '\1um'
'/(n)ews$/i': '\1ews'
'/s$/i': ''
INFLECTOR_UNCOUNTABLE: ['équipement', 'information', 'riz', 'argent', 'espèces', 'séries', 'poisson', 'mouton']
/(quiz)zes$/i: '\1'
/(matr)ices$/i: '\1ix'
/(vert|ind)ices$/i: '\1ex'
/^(ox)en/i: '\1'
/(alias|status)es$/i: '\1'
"/([octop|vir])i$/i": '\1us'
/(cris|ax|test)es$/i: '\1is'
/(shoe)s$/i: '\1'
/(o)es$/i: '\1'
/(bus)es$/i: '\1'
"/([m|l])ice$/i": '\1ouse'
/(x|ch|ss|sh)es$/i: '\1'
/(m)ovies$/i: '\1ovie'
/(s)eries$/i: '\1eries'
"/([^aeiouy]|qu)ies$/i": '\1y'
"/([lr])ves$/i": '\1f'
/(tive)s$/i: '\1'
/(hive)s$/i: '\1'
"/([^f])ves$/i": '\1fe'
/(^analy)ses$/i: '\1sis'
/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i: '\1\2sis'
"/([ti])a$/i": '\1um'
/(n)ews$/i: '\1ews'
INFLECTOR_UNCOUNTABLE:
- équipement
- informations
- riz
- argent
- espèces
- séries
- poisson
- mouton
INFLECTOR_IRREGULAR:
'person': 'personnes'
'man': 'hommes'
'child': 'enfants'
'sex': 'sexes'
'move': 'déplacements'
person: personnes
man: hommes
child: enfants
sex: sexes
move: déplacements
INFLECTOR_ORDINALS:
'default': 'ème'
'first': 'er'
'second': 'nd'
'third': 'ème'
default: ème
first: er
second: ème
third: ème
NICETIME:
NO_DATE_PROVIDED: Aucune date
BAD_DATE: Date erronée
AGO: plus tôt
FROM_NOW: à partir de maintenant
SECOND: seconde
MINUTE: minute
HOUR: heure
DAY: jour
WEEK: semaine
MONTH: mois
YEAR: an
DECADE: décennie
SEC: s
MIN: m
HR: h
DAY: j
WK: s
MO: m
YR: a
DEC: d
SECOND_PLURAL: secondes
MINUTE_PLURAL: minutes
HOUR_PLURAL: heures
DAY_PLURAL: jours
WEEK_PLURAL: semaines
MONTH_PLURAL: mois
YEAR_PLURAL: années
DECADE_PLURAL: décennies
SEC_PLURAL: s
MIN_PLURAL: m
HR_PLURAL: h
DAY_PLURAL: j
WK_PLURAL: s
MO_PLURAL: m
YR_PLURAL: a
DEC_PLURAL: d
NO_DATE_PROVIDED: Aucune date fournie
BAD_DATE: Date erronée
AGO: plus tôt
FROM_NOW: à partir de maintenant
SECOND: seconde
MINUTE: minute
HOUR: heure
DAY: jour
WEEK: semaine
MONTH: mois
YEAR: année
DECADE: décennie
SEC: s
MIN: m
HR: h
WK: sem
MO: m
YR: an
DEC: déc
SECOND_PLURAL: secondes
MINUTE_PLURAL: minutes
HOUR_PLURAL: heures
DAY_PLURAL: jours
WEEK_PLURAL: semaines
MONTH_PLURAL: mois
YEAR_PLURAL: années
DECADE_PLURAL: décennies
SEC_PLURAL: s
MIN_PLURAL: m
HR_PLURAL: h
WK_PLURAL: sem
MO_PLURAL: mois
YR_PLURAL: a
DEC_PLURAL: décs
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']
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

View File

@@ -1,52 +1,75 @@
---
INFLECTOR_UNCOUNTABLE:
- oprema
- informacije
- riža
- novac
- vrsta
- serija
- riba
- ovca
INFLECTOR_IRREGULAR:
'person': 'Osoba'
'man': 'Čovjek'
'child': 'Dijete'
'sex': 'Spol'
'move': 'Pomakni'
person: osobe
man: ljudi
child: djeca
sex: spolovi
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
NO_DATE_PROVIDED: Datum nije upisan
BAD_DATE: Pogrešan datum
AGO: prije
FROM_NOW: od sada
SECOND: sekunda
MINUTE: minuta
HOUR: sat
DAY: dan
WEEK: tjedan
MONTH: mjesec
YEAR: godina
DECADE: desetljeće
SEC: sek
HR: sat
WK: t
MO: m
YR: g
DEC: des
SECOND_PLURAL: sekundi
MINUTE_PLURAL: minuta
HOUR_PLURAL: sati
DAY_PLURAL: dan
WEEK_PLURAL: tjedana
MONTH_PLURAL: mjeseci
YEAR_PLURAL: godina
DECADE_PLURAL: desetljeća
SEC_PLURAL: sek
MIN_PLURAL: min
HR_PLURAL: sat
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
VALIDATION_FAIL: '<b>Validacija nije uspjela:</b>'
INVALID_INPUT: Pogrešan unos u
MISSING_REQUIRED_FIELD: 'Nedostaje obavezno polje:'
MONTHS_OF_THE_YEAR:
- Siječanj
- Veljača
- Ožujak
- Travanj
- Svibanj
- Lipanj
- Srpanj
- Kolovoz
- Rujan
- Listopad
- Studeni
- Prosinac
DAYS_OF_THE_WEEK:
- Ponedjeljak
- Utorak
- Srijeda
- Četvrtak
- Petak
- Subota
- Nedjelja

View File

@@ -1,53 +1,65 @@
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```"
---
FRONTMATTER_ERROR_PAGE: |
---
cím: %1$s
---
# Hiba: Érvénytelen Frontmatter
Elérési út: `%2$s`
**%3$s**
```
%4$s
```
INFLECTOR_IRREGULAR:
'person': 'személyek'
'man': 'férfiak'
'child': 'gyerekek'
'sex': 'nemek'
'move': 'lépések'
person: személyek
man: férfiak
child: gyerekek
sex: nemek
move: lépések
INFLECTOR_ORDINALS:
'default': '.'
'first': '.'
'second': '.'
'third': '.'
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
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: ó
WK: hét
MO: hó
YR: év
DEC: évt
SECOND_PLURAL: másodperc
MINUTE_PLURAL: perc
HOUR_PLURAL: óra
DAY_PLURAL: nap
WEEK_PLURAL: hét
MONTH_PLURAL: hónap
YEAR_PLURAL: év
DECADE_PLURAL: évtized
SEC_PLURAL: mp
MIN_PLURAL: perc
HR_PLURAL: ó
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:
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

@@ -1,27 +1,46 @@
---
NICETIME:
NO_DATE_PROVIDED: Nessuna data fornita
BAD_DATE: Data errata
AGO: fa
FROM_NOW: da adesso
SECOND: secondo
MINUTE: minuto
HOUR: ora
DAY: giorno
WEEK: settimana
MONTH: mese
YEAR: anno
DECADE: decade
SECOND_PLURAL: secondi
MINUTE_PLURAL: minuti
HOUR_PLURAL: ore
DAY_PLURAL: giorni
WEEK_PLURAL: settimane
MONTH_PLURAL: mesi
YEAR_PLURAL: anni
DECADE_PLURAL: decadi
NO_DATE_PROVIDED: Nessuna data fornita
BAD_DATE: Data errata
AGO: fa
FROM_NOW: da adesso
SECOND: secondo
MINUTE: minuto
HOUR: ora
DAY: giorno
WEEK: settimana
MONTH: mese
YEAR: anno
SECOND_PLURAL: secondi
MINUTE_PLURAL: minuti
HOUR_PLURAL: ore
DAY_PLURAL: giorni
WEEK_PLURAL: settimane
MONTH_PLURAL: mesi
YEAR_PLURAL: anni
DECADE_PLURAL: decadi
FORM:
VALIDATION_FAIL: <b>Validazione fallita:</b>
INVALID_INPUT: Input invalido in
MISSING_REQUIRED_FIELD: Campo richiesto mancante:
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']
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

69
system/languages/lt.yaml Normal file
View File

@@ -0,0 +1,69 @@
---
INFLECTOR_UNCOUNTABLE:
2: ryžiai
3: pinigai
4: prieskoniai
5: serijos
6: žuvis
7: avis
INFLECTOR_IRREGULAR:
person: žmonės
man: žmogus
child: vaikai
sex: lytys
move: juda
NICETIME:
NO_DATE_PROVIDED: Nenurodyta data
BAD_DATE: Neteisinga data
AGO: prieš
FROM_NOW: nuo dabar
SECOND: sekundė
MINUTE: minutė
HOUR: valanda
DAY: diena
WEEK: savaitė
MONTH: mėnuo
YEAR: metai
DECADE: dešimtmetis
SEC: sek
MIN: min
HR: val
WK: sav
MO: mėn
YR: m
MINUTE_PLURAL: minutės
HOUR_PLURAL: valandos
DAY_PLURAL: dienos
WEEK_PLURAL: savaitės
MONTH_PLURAL: mėnesiai
YEAR_PLURAL: metai
DECADE_PLURAL: dešimtmečiai
SEC_PLURAL: sek
MIN_PLURAL: min
HR_PLURAL: val
WK_PLURAL: sav
MO_PLURAL: mėn
YR_PLURAL: m
FORM:
MISSING_REQUIRED_FIELD: 'Būtina užpildyti laukelį:'
MONTHS_OF_THE_YEAR:
- Sausis
- Vasaris
- Kovas
- Balandis
- Gegužė
- Birželis
- Liepa
- Rugpjūtis
- Rugsėjis
- Spalis
- Lakpritis
- Gruodis
DAYS_OF_THE_WEEK:
- Pirmadienis
- Antradienis
- Trečiadienis
- Ketvirtadienis
- Penktadienis
- Šeštadienis
- Sekmadienis

View File

@@ -1,45 +1,51 @@
---
INFLECTOR_IRREGULAR:
'person': 'personen'
'man': 'mensen'
'child': 'kinderen'
'sex': 'geslacht'
'move': 'verplaatsen'
person: personen
man: mensen
child: kinderen
sex: geslacht
move: verplaatsen
NICETIME:
NO_DATE_PROVIDED: geen datum opgegeven
BAD_DATE: Datumformaat onjuist
AGO: geleden
FROM_NOW: vanaf nu
SECOND: seconde
MINUTE: minuut
HOUR: uur
DAY: dag
WEEK: week
MONTH: maand
YEAR: jaar
DECADE: decenium
SEC: sec
MIN: min
HR: hr
DAY: dag
WK: wk
MO: ma
YR: yr
DEC: dec
SECOND_PLURAL: seconden
MINUTE_PLURAL: minuten
HOUR_PLURAL: uren
DAY_PLURAL: dagen
WEEK_PLURAL: weken
MONTH_PLURAL: maanden
YEAR_PLURAL: jaren
DECADE_PLURAL: decennia
SEC_PLURAL: seconden
MIN_PLURAL: minuten
HR_PLURAL: uren
DAY_PLURAL: dagen
WK_PLURAL: weken
MO_PLURAL: maanden
YR_PLURAL: jaren
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']
NO_DATE_PROVIDED: geen datum opgegeven
BAD_DATE: Datumformaat onjuist
AGO: geleden
FROM_NOW: vanaf nu
SECOND: seconde
MINUTE: minuut
HOUR: uur
DAY: dag
MONTH: maand
YEAR: jaar
DECADE: decenium
MO: ma
SECOND_PLURAL: seconden
MINUTE_PLURAL: minuten
HOUR_PLURAL: uren
DAY_PLURAL: dagen
WEEK_PLURAL: weken
MONTH_PLURAL: maanden
YEAR_PLURAL: jaren
DECADE_PLURAL: decennia
SEC_PLURAL: seconden
MIN_PLURAL: minuten
HR_PLURAL: uren
WK_PLURAL: weken
MO_PLURAL: maanden
YR_PLURAL: jaren
MONTHS_OF_THE_YEAR:
0: Januari
1: Februari
2: Maart
4: Mei
5: Juni
6: Juli
7: Augustus
9: Oktober
DAYS_OF_THE_WEEK:
- Maandag
- Dinsdag
- Woensdag
- Donderdag
- Vrijdag
- Zaterdag
- Zondag

91
system/languages/no.yaml Normal file
View File

@@ -0,0 +1,91 @@
---
FRONTMATTER_ERROR_PAGE: |
---
Tittel: %1$s
---
# Feilmelding: Ugyldig Frontmatter
Pane: '%2$s'
**%3$s **
```
%4$s
```
INFLECTOR_PLURALS:
/(quiz)$/i: '\1zes'
/^(ox)$/i: '\1en'
INFLECTOR_UNCOUNTABLE:
- utstyr
- informasjon
- ris
- penger
- arter
- serier
- fisk
- sau
INFLECTOR_IRREGULAR:
person: folk
man: menn
child: barn
sex: kjønn
move: trekk
NICETIME:
NO_DATE_PROVIDED: Ingen dato gitt
BAD_DATE: Dårlig dato
AGO: siden
FROM_NOW: fra nå
SECOND: sekund
MINUTE: minutt
HOUR: time
DAY: dag
WEEK: uke
MONTH: måned
YEAR: år
DECADE: tiår
SEC: sek
MIN: min
HR: t
WK: uke
MO:
YR: år
DEC: des
SECOND_PLURAL: sekunder
MINUTE_PLURAL: minutter
HOUR_PLURAL: timer
DAY_PLURAL: dager
WEEK_PLURAL: uker
MONTH_PLURAL: måneder
YEAR_PLURAL: år
DECADE_PLURAL: tiår
SEC_PLURAL: sek
MIN_PLURAL: min
HR_PLURAL: timer
WK_PLURAL: uker
YR_PLURAL: år
FORM:
VALIDATION_FAIL: '<b>Validering mislyktes:</b>'
INVALID_INPUT: Ugyldig innhold i
MISSING_REQUIRED_FIELD: 'Mangler påkrevd felt:'
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

@@ -1,2 +1,75 @@
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']
---
FRONTMATTER_ERROR_PAGE: |
---
title: %1$s
---
# Error: Nieprawidłowy Frontmatter
Path: `%2$s`
**%3$s**
```
%4$s
```
NICETIME:
NO_DATE_PROVIDED: Nie podano daty
BAD_DATE: Zła data
AGO: temu
FROM_NOW: od teraz
SECOND: sekunda
MINUTE: minuta
HOUR: godzina
DAY: dzień
WEEK: tydzień
MONTH: miesiąc
YEAR: rok
DECADE: dekada
SEC: sek
MIN: min
HR: godz
WK: tydź
MO: mieś
YR: rok
DEC: dekada
SECOND_PLURAL: sekund
MINUTE_PLURAL: minut
HOUR_PLURAL: godzin
DAY_PLURAL: dni
WEEK_PLURAL: tygodnie
MONTH_PLURAL: miesięcy
YEAR_PLURAL: lat
DECADE_PLURAL: dekad
SEC_PLURAL: sekund
MIN_PLURAL: minut
HR_PLURAL: godz
WK_PLURAL: tyg
MO_PLURAL: mieś
YR_PLURAL: lat
DEC_PLURAL: dekad
FORM:
VALIDATION_FAIL: '<b>Weryfikacja nie powiodła się:</b>'
INVALID_INPUT: Nieprawidłowe dane w
MISSING_REQUIRED_FIELD: 'Opuszczono wymagane pole:'
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

View File

@@ -1,2 +1,56 @@
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']
---
INFLECTOR_UNCOUNTABLE:
1: informação
2: arroz
3: dinheiro
INFLECTOR_IRREGULAR:
man: homens
sex: sexos
NICETIME:
SECOND: segundo
MINUTE: minuto
HOUR: hora
DAY: dia
WEEK: semana
MONTH: mês
YEAR: ano
DECADE: década
SEC: seg
MIN: mín
MO: mês
YR: ano
SECOND_PLURAL: segundos
MINUTE_PLURAL: minutos
HOUR_PLURAL: horas
DAY_PLURAL: dias
WEEK_PLURAL: semanas
MONTH_PLURAL: meses
YEAR_PLURAL: anos
DECADE_PLURAL: décadas
SEC_PLURAL: seg
MIN_PLURAL: mins
HR_PLURAL: hrs
YR_PLURAL: anos
FORM:
VALIDATION_FAIL: '<b>Validação falhada: </b>'
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

View File

@@ -1,2 +1,21 @@
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ă']
---
MONTHS_OF_THE_YEAR:
0: Ianuarie
1: Februarie
2: Martie
3: Aprilue
4: Mai
5: Iunie
6: Iulie
8: Septembrie
9: Octombrie
10: Noiembrie
11: Decembrie
DAYS_OF_THE_WEEK:
- Luni
- Marti
- Miercuri
- Joi
- Vineri
- Sâmbătă
- Duminică

View File

@@ -1,45 +1,67 @@
---
INFLECTOR_IRREGULAR:
'person': 'люди'
'man': 'человек'
'child': 'ребенок'
'sex': 'пол'
'move': 'движется'
person: люди
man: человек
child: ребенок
sex: пол
move: движется
NICETIME:
NO_DATE_PROVIDED: Дата не указана
BAD_DATE: Неверная дата
AGO: назад
FROM_NOW: теперь
SECOND: секунда
MINUTE: минута
HOUR: час
DAY: день
WEEK: неделя
MONTH: месяц
YEAR: год
DECADE: десятилетие
SEC: с
MIN: мин
HR: ч
DAY: д
WK: нед
MO: мес
YR: г.
DEC: гг.
SECOND_PLURAL: секунды
MINUTE_PLURAL: минуты
HOUR_PLURAL: часы
DAY_PLURAL: дни
WEEK_PLURAL: недели
MONTH_PLURAL: месяцы
YEAR_PLURAL: годы
DECADE_PLURAL: десятилетия
SEC_PLURAL: с
MIN_PLURAL: мин
HR_PLURAL: ч
DAY_PLURAL: д
WK_PLURAL: нед
MO_PLURAL: мес
YR_PLURAL: г.
DEC_PLURAL: гг.
MONTHS_OF_THE_YEAR: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь']
DAYS_OF_THE_WEEK: ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье']
NO_DATE_PROVIDED: Дата не указана
BAD_DATE: Неверная дата
AGO: назад
FROM_NOW: теперь
SECOND: секунда
MINUTE: минута
HOUR: час
DAY: д
WEEK: неделя
MONTH: месяц
YEAR: год
DECADE: десятилетие
SEC: с
MIN: мин
HR: ч
WK: нед
MO: мес
YR: г.
DEC: гг.
SECOND_PLURAL: секунды
MINUTE_PLURAL: минуты
HOUR_PLURAL: часы
DAY_PLURAL: д
WEEK_PLURAL: недели
MONTH_PLURAL: месяцы
YEAR_PLURAL: годы
DECADE_PLURAL: десятилетия
SEC_PLURAL: с
MIN_PLURAL: мин
HR_PLURAL: ч
WK_PLURAL: нед
MO_PLURAL: мес
YR_PLURAL: г.
DEC_PLURAL: гг.
FORM:
VALIDATION_FAIL: '<b>Проверка не удалась:</b>'
INVALID_INPUT: Неверный ввод в
MISSING_REQUIRED_FIELD: 'Отсутствует необходимое поле:'
MONTHS_OF_THE_YEAR:
- Январь
- Февраль
- Март
- Апрель
- Май
- Июнь
- Июль
- Август
- Сентябрь
- Октябрь
- Ноябрь
- Декабрь
DAYS_OF_THE_WEEK:
- Понедельник
- Вторник
- Среда
- Четверг
- Пятница
- Суббота
- Воскресенье

1
system/languages/sk.yaml Normal file
View File

@@ -0,0 +1 @@
---

3
system/languages/sv.yaml Normal file
View File

@@ -0,0 +1,3 @@
---
NICETIME:
DAY: dag

View File

@@ -1,37 +1,36 @@
---
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
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
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
WK_PLURAL: hft
MO_PLURAL: ay
YR_PLURAL: yl
DEC_PLURAL: onyl

View File

@@ -8,6 +8,7 @@ use Grav\Common\Config\Config;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RegexIterator;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
define('CSS_ASSET', true);
define('JS_ASSET', false);
@@ -64,11 +65,12 @@ class Assets
protected $js_pipeline = false;
// The asset holding arrays
protected $collections = array();
protected $css = array();
protected $js = array();
protected $inline_css = array();
protected $inline_js = array();
protected $collections = [];
protected $css = [];
protected $js = [];
protected $inline_css = [];
protected $inline_js = [];
protected $imports = [];
// Some configuration variables
protected $config;
@@ -84,10 +86,15 @@ class Assets
protected $js_minify = true;
// Arrays to hold assets that should NOT be pipelined
protected $css_no_pipeline = array();
protected $js_no_pipeline = array();
protected $css_no_pipeline = [];
protected $js_no_pipeline = [];
public function __construct(array $options = array())
/**
* Assets constructor.
*
* @param array $options
*/
public function __construct(array $options = [])
{
// Forward config options
if ($options) {
@@ -163,7 +170,6 @@ class Assets
$this->timestamp = '?' . self::getGrav()['cache']->getKey();
}
return $this;
}
@@ -177,10 +183,10 @@ class Assets
$base_url = self::getGrav()['base_url'];
$asset_config = (array)$config->get('system.assets');
/** @var Locator $locator */
/** @var UniformResourceLocator $locator */
$locator = self::$grav['locator'];
$this->assets_dir = self::getGrav()['locator']->findResource('asset://') . DS;
$this->assets_url = self::getGrav()['locator']->findResource('asset://', false);
$this->assets_dir = $locator->findResource('asset://') . DS;
$this->assets_url = $locator->findResource('asset://', false);
$this->config($asset_config);
$this->base_url = $base_url . '/';
@@ -237,9 +243,9 @@ class Assets
* You may add more than one asset passing an array as argument.
*
* @param mixed $asset
* @param int $priority the priority, bigger comes first
* @param bool $pipeline false if this should not be pipelined
* @param null $group
* @param int $priority the priority, bigger comes first
* @param bool $pipeline false if this should not be pipelined
* @param null $group
*
* @return $this
*/
@@ -249,9 +255,11 @@ class Assets
foreach ($asset as $a) {
$this->addCss($a, $priority, $pipeline, $group);
}
return $this;
} elseif (isset($this->collections[$asset])) {
$this->add($this->collections[$asset], $priority, $pipeline, $group);
$this->addCss($this->collections[$asset], $priority, $pipeline, $group);
return $this;
}
@@ -268,12 +276,12 @@ class Assets
'asset' => $asset,
'priority' => intval($priority ?: 10),
'order' => count($this->css),
'pipeline' => (bool) $pipeline,
'group' => $group ?: 'head'
'pipeline' => (bool)$pipeline,
'group' => $group ?: 'head'
];
// check for dynamic array and merge with defaults
if (func_num_args() == 2) {
if (func_num_args() > 1) {
$dynamic_arg = func_get_arg(1);
if (is_array($dynamic_arg)) {
$data = array_merge($data, $dynamic_arg);
@@ -294,11 +302,12 @@ class Assets
* It checks for duplicates.
* You may add more than one asset passing an array as argument.
*
* @param mixed $asset
* @param int $priority the priority, bigger comes first
* @param bool $pipeline false if this should not be pipelined
* @param string $loading how the asset is loaded (async/defer)
* @param string $group name of the group
* @param mixed $asset
* @param int $priority the priority, bigger comes first
* @param bool $pipeline false if this should not be pipelined
* @param string $loading how the asset is loaded (async/defer)
* @param string $group name of the group
*
* @return $this
*/
public function addJs($asset, $priority = null, $pipeline = true, $loading = null, $group = null)
@@ -307,9 +316,11 @@ class Assets
foreach ($asset as $a) {
$this->addJs($a, $priority, $pipeline, $loading, $group);
}
return $this;
} elseif (isset($this->collections[$asset])) {
$this->add($this->collections[$asset], $priority, $pipeline, $loading, $group);
$this->addJs($this->collections[$asset], $priority, $pipeline, $loading, $group);
return $this;
}
@@ -326,16 +337,16 @@ class Assets
'asset' => $asset,
'priority' => intval($priority ?: 10),
'order' => count($this->js),
'pipeline' => (bool) $pipeline,
'pipeline' => (bool)$pipeline,
'loading' => $loading ?: '',
'group' => $group ?: 'head'
'group' => $group ?: 'head'
];
// check for dynamic array and merge with defaults
if (func_num_args() == 2) {
if (func_num_args() > 1) {
$dynamic_arg = func_get_arg(1);
if (is_array($dynamic_arg)) {
$data = array_merge($data, $dynamic_arg);
$data = array_merge($data, $dynamic_arg);
}
}
@@ -350,9 +361,9 @@ class Assets
/**
* Convenience wrapper for async loading of JavaScript
*
* @param $asset
* @param int $priority
* @param bool $pipeline
* @param $asset
* @param int $priority
* @param bool $pipeline
* @param string $group name of the group
*
* @deprecated Please use dynamic method with ['loading' => 'async']
@@ -367,9 +378,9 @@ class Assets
/**
* Convenience wrapper for deferred loading of JavaScript
*
* @param $asset
* @param int $priority
* @param bool $pipeline
* @param $asset
* @param int $priority
* @param bool $pipeline
* @param string $group name of the group
*
* @deprecated Please use dynamic method with ['loading' => 'defer']
@@ -388,8 +399,8 @@ class Assets
* For adding chunks of string-based inline CSS
*
* @param mixed $asset
* @param int $priority the priority, bigger comes first
* @param null $group
* @param int $priority the priority, bigger comes first
* @param null $group
*
* @return $this
*/
@@ -398,21 +409,20 @@ class Assets
$asset = trim($asset);
if (is_a($asset, 'Twig_Markup')) {
preg_match(self::HTML_TAG_REGEX, $asset, $matches );
if (isset($matches[3])) {
preg_match(self::HTML_TAG_REGEX, $asset, $matches);
if (isset($matches[3])) {
$asset = $matches[3];
}
}
$data = [
'priority' => intval($priority ?: 10),
'order' => count($this->inline_css),
'asset' => $asset,
'group' => $group ?: 'head'
'priority' => intval($priority ?: 10),
'order' => count($this->inline_css),
'asset' => $asset,
'group' => $group ?: 'head'
];
// check for dynamic array and merge with defaults
$count_args = func_num_args();
if (func_num_args() == 2) {
$dynamic_arg = func_get_arg(1);
if (is_array($dynamic_arg)) {
@@ -436,7 +446,7 @@ class Assets
*
* @param mixed $asset
* @param int $priority the priority, bigger comes first
* @param string $group name of the group
* @param string $group name of the group
*
* @return $this
*/
@@ -445,8 +455,8 @@ class Assets
$asset = trim($asset);
if (is_a($asset, 'Twig_Markup')) {
preg_match(self::HTML_TAG_REGEX, $asset, $matches );
if (isset($matches[3])) {
preg_match(self::HTML_TAG_REGEX, $asset, $matches);
if (isset($matches[3])) {
$asset = $matches[3];
}
}
@@ -455,11 +465,10 @@ class Assets
'asset' => $asset,
'priority' => intval($priority ?: 10),
'order' => count($this->js),
'group' => $group ?: 'head'
'group' => $group ?: 'head'
];
// check for dynamic array and merge with defaults
$count_args = func_num_args();
if (func_num_args() == 2) {
$dynamic_arg = func_get_arg(1);
if (is_array($dynamic_arg)) {
@@ -479,7 +488,7 @@ class Assets
* Build the CSS link tags.
*
* @param string $group name of the group
* @param array $attributes
* @param array $attributes
*
* @return string
*/
@@ -495,6 +504,7 @@ class Assets
if ($a['priority'] == $b['priority']) {
return $b['order'] - $a['order'];
}
return $a['priority'] - $b['priority'];
});
@@ -502,6 +512,7 @@ class Assets
if ($a['priority'] == $b['priority']) {
return $b['order'] - $a['order'];
}
return $a['priority'] - $b['priority'];
});
}
@@ -552,7 +563,7 @@ class Assets
* Build the JavaScript script tags.
*
* @param string $group name of the group
* @param array $attributes
* @param array $attributes
*
* @return string
*/
@@ -567,6 +578,7 @@ class Assets
if ($a['priority'] == $b['priority']) {
return $b['order'] - $a['order'];
}
return $a['priority'] - $b['priority'];
});
@@ -574,6 +586,7 @@ class Assets
if ($a['priority'] == $b['priority']) {
return $b['order'] - $a['order'];
}
return $a['priority'] - $b['priority'];
});
@@ -592,7 +605,7 @@ class Assets
}
foreach ($this->js_no_pipeline as $file) {
if ($group && $file['group'] == $group) {
$output .= '<script src="' . $file['asset'] . $this->timestamp . '"' . $attributes . ' ' . $file['loading']. '></script>' . "\n";
$output .= '<script src="' . $file['asset'] . $this->timestamp . '"' . $attributes . ' ' . $file['loading'] . '></script>' . "\n";
}
}
} else {
@@ -618,9 +631,11 @@ class Assets
}
/**
* Minify and concatenate CSS.
* Minify and concatenate CSS
*
* @return string
* @param string $group
*
* @return bool|string
*/
protected function pipelineCss($group = 'head')
{
@@ -679,6 +694,7 @@ class Assets
// Write file
if (strlen(trim($buffer)) > 0) {
file_put_contents($absolute_path, $buffer);
return $relative_path . $key;
} else {
return false;
@@ -688,6 +704,8 @@ class Assets
/**
* Minify and concatenate JS files.
*
* @param string $group
*
* @return string
*/
protected function pipelineJs($group = 'head')
@@ -737,6 +755,7 @@ class Assets
// Write file
if (strlen(trim($buffer)) > 0) {
file_put_contents($absolute_path, $buffer);
return $relative_path . $key;
} else {
return false;
@@ -782,9 +801,7 @@ class Assets
*/
public function exists($asset)
{
if (isset($this->collections[$asset]) ||
isset($this->css[$asset]) ||
isset($this->js[$asset])) {
if (isset($this->collections[$asset]) || isset($this->css[$asset]) || isset($this->js[$asset])) {
return true;
} else {
return false;
@@ -826,7 +843,8 @@ class Assets
*/
public function resetJs()
{
$this->js = array();
$this->js = [];
$this->inline_js = [];
return $this;
}
@@ -838,15 +856,28 @@ class Assets
*/
public function resetCss()
{
$this->css = array();
$this->css = [];
$this->inline_css = [];
return $this;
}
/**
* Add all CSS assets within $directory (relative to public dir).
* Add all JavaScript assets within $directory
*
* @param string $directory Relative to $this->public_dir
* @param string $directory Relative to the Grav root path, or a stream identifier
*
* @return $this
*/
public function addDirJs($directory)
{
return $this->addDir($directory, self::JS_REGEX);
}
/**
* Add all CSS assets within $directory
*
* @param string $directory Relative to the Grav root path, or a stream identifier
*
* @return $this
*/
@@ -858,7 +889,7 @@ class Assets
/**
* Add all assets matching $pattern within $directory.
*
* @param string $directory Relative to $this->public_dir
* @param string $directory Relative to the Grav root path, or a stream identifier
* @param string $pattern (regex)
*
* @return $this
@@ -866,13 +897,15 @@ class Assets
*/
public function addDir($directory, $pattern = self::DEFAULT_REGEX)
{
// Check if public_dir exists
if (!is_dir($this->assets_dir)) {
throw new Exception('Assets: Public dir not found');
$root_dir = rtrim(ROOT_DIR, '/');
// Check if $directory is a stream.
if (strpos($directory, '://')) {
$directory = self::$grav['locator']->findResource($directory, null);
}
// Get files
$files = $this->rglob($this->assets_dir . DIRECTORY_SEPARATOR . $directory, $pattern, $this->assets_dir);
$files = $this->rglob($root_dir . DIRECTORY_SEPARATOR . $directory, $pattern, $root_dir . '/');
// No luck? Nothing to do
if (!$files) {
@@ -881,27 +914,25 @@ class Assets
// Add CSS files
if ($pattern === self::CSS_REGEX) {
$this->css = array_unique(array_merge($this->css, $files));
foreach ($files as $file) {
$this->addCss($file);
}
return $this;
}
// Add JavaScript files
if ($pattern === self::JS_REGEX) {
$this->js = array_unique(array_merge($this->js, $files));
foreach ($files as $file) {
$this->addJs($file);
}
return $this;
}
// Unknown pattern. We must poll to know the extension :(
// Unknown pattern.
foreach ($files as $asset) {
$info = pathinfo($asset);
if (isset($info['extension'])) {
$ext = strtolower($info['extension']);
if ($ext === 'css' && !in_array($asset, $this->css)) {
$this->css[] = $asset;
} elseif ($ext === 'js' && !in_array($asset, $this->js)) {
$this->js[] = $asset;
}
}
$this->add($asset);
}
return $this;
@@ -918,8 +949,8 @@ class Assets
*/
protected function isRemoteLink($link)
{
return ('http://' === substr($link, 0, 7) || 'https://' === substr($link, 0, 8)
|| '//' === substr($link, 0, 2));
return ('http://' === substr($link, 0, 7) || 'https://' === substr($link, 0, 8) || '//' === substr($link, 0,
2));
}
/**
@@ -972,18 +1003,18 @@ class Assets
* Download and concatenate the content of several links.
*
* @param array $links
* @param bool $css
* @param bool $css
*
* @return string
*/
protected function gatherLinks(array $links, $css = true)
{
$buffer = '';
$local = true;
foreach ($links as $asset) {
$relative_dir = '';
$link = $asset['asset'];
$relative_path = $link;
@@ -1034,8 +1065,8 @@ class Assets
/**
* Finds relative CSS urls() and rewrites the URL with an absolute one
*
* @param $file the css source file
* @param $relative_path relative path to the css file
* @param string $file the css source file
* @param string $relative_path relative path to the css file
*
* @return mixed
*/
@@ -1046,23 +1077,19 @@ class Assets
// Find any css url() elements, grab the URLs and calculate an absolute path
// Then replace the old url with the new one
$file = preg_replace_callback(
self::CSS_URL_REGEX,
function ($matches) use ($relative_path) {
$file = preg_replace_callback(self::CSS_URL_REGEX, function ($matches) use ($relative_path) {
$old_url = $matches[1];
$old_url = $matches[1];
// ensure this is not a data url
if (strpos($old_url, 'data:') === 0) {
return $matches[0];
}
// ensure this is not a data url
if (strpos($old_url, 'data:') === 0) {
return $matches[0];
}
$new_url = $this->base_url . ltrim(Utils::normalizePath($relative_path . '/' . $old_url), '/');
$new_url = $this->base_url . ltrim(Utils::normalizePath($relative_path . '/' . $old_url), '/');
return str_replace($old_url, $new_url, $matches[0]);
},
$file
);
return str_replace($old_url, $new_url, $matches[0]);
}, $file);
return $file;
}
@@ -1076,16 +1103,13 @@ class Assets
*/
protected function moveImports($file)
{
$this->imports = array();
$this->imports = [];
$file = preg_replace_callback(
self::CSS_IMPORT_REGEX,
function ($matches) {
$this->imports[] = $matches[0];
return '';
},
$file
);
$file = preg_replace_callback(self::CSS_IMPORT_REGEX, function ($matches) {
$this->imports[] = $matches[0];
return '';
}, $file);
return implode("\n", $this->imports) . "\n\n" . $file;
}
@@ -1101,17 +1125,10 @@ class Assets
*/
protected function rglob($directory, $pattern, $ltrim = null)
{
$iterator = new RegexIterator(
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$directory,
FilesystemIterator::SKIP_DOTS
)
),
$pattern
);
$iterator = new RegexIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory,
FilesystemIterator::SKIP_DOTS)), $pattern);
$offset = strlen($ltrim);
$files = array();
$files = [];
foreach ($iterator as $file) {
$files[] = substr($file->getPathname(), $offset);
@@ -1120,18 +1137,6 @@ class Assets
return $files;
}
/**
* Add all JavaScript assets within $directory.
*
* @param string $directory Relative to $this->public_dir
*
* @return $this
*/
public function addDirJs($directory)
{
return $this->addDir($directory, self::JS_REGEX);
}
/**
* Sets the state of CSS Pipeline
*
@@ -1139,7 +1144,7 @@ class Assets
*/
public function setCssPipeline($value)
{
$this->css_pipeline = (bool) $value;
$this->css_pipeline = (bool)$value;
}
/**
@@ -1149,7 +1154,7 @@ class Assets
*/
public function setJsPipeline($value)
{
$this->js_pipeline = (bool) $value;
$this->js_pipeline = (bool)$value;
}
/**
@@ -1159,9 +1164,12 @@ class Assets
*/
public function setTimestamp($value)
{
$this->timestamp = '?'.$value;
$this->timestamp = '?' . $value;
}
/**
* @return string
*/
public function __toString()
{
return '';

View File

@@ -29,6 +29,14 @@ class ZipBackup
'.idea'
];
/**
* Backup
*
* @param null $destination
* @param callable|null $messager
*
* @return null|string
*/
public static function backup($destination = null, callable $messager = null)
{
if (!$destination) {

View File

@@ -2,13 +2,20 @@
namespace Grav\Common;
/**
* Simple wrapper for the very simple parse_user_agent() function
* Handles browser and platform versions
*
* Internally uses the PhpUserAgent package https://github.com/donatj/PhpUserAgent
*
* @author RocketTHeme
* @licence MIT
*/
class Browser
{
protected $useragent = [];
/**
* Browser constructor.
*/
public function __construct()
{
try {
@@ -18,29 +25,99 @@ class Browser
}
}
/**
* Get the current browser identifier
*
* Currently detected browsers:
*
* Android Browser
* BlackBerry Browser
* Camino
* Kindle / Silk
* Firefox / Iceweasel
* Safari
* Internet Explorer
* IEMobile
* Chrome
* Opera
* Midori
* Vivaldi
* TizenBrowser
* Lynx
* Wget
* Curl
*
* @return string the lowercase browser name
*/
public function getBrowser()
{
return strtolower($this->useragent['browser']);
}
/**
* Get the current platform identifier
*
* Currently detected platforms:
*
* Desktop
* -> Windows
* -> Linux
* -> Macintosh
* -> Chrome OS
* Mobile
* -> Android
* -> iPhone
* -> iPad / iPod Touch
* -> Windows Phone OS
* -> Kindle
* -> Kindle Fire
* -> BlackBerry
* -> Playbook
* -> Tizen
* Console
* -> Nintendo 3DS
* -> New Nintendo 3DS
* -> Nintendo Wii
* -> Nintendo WiiU
* -> PlayStation 3
* -> PlayStation 4
* -> PlayStation Vita
* -> Xbox 360
* -> Xbox One
*
* @return string the lowercase platform name
*/
public function getPlatform()
{
return strtolower($this->useragent['platform']);
}
/**
* Get the current full version identifier
*
* @return string the browser full version identifier
*/
public function getLongVersion()
{
return $this->useragent['version'];
}
/**
* Get the current major version identifier
*
* @return string the browser major version identifier
*/
public function getVersion()
{
$version = explode('.', $this->getLongVersion());
return intval($version[0]);
}
/**
* Determine if the request comes from a human, or from a bot/crawler
*
* @return bool
*/
public function isHuman()
{

View File

@@ -1,7 +1,7 @@
<?php
namespace Grav\Common;
use \Doctrine\Common\Cache\Cache as DoctrineCache;
use \Doctrine\Common\Cache as DoctrineCache;
use Grav\Common\Config\Config;
use Grav\Common\Filesystem\Folder;
@@ -16,7 +16,7 @@ use Grav\Common\Filesystem\Folder;
* MemCacheD
* FileSystem
*
* @author RocketTheme
* @author RocketTheme
* @license MIT
*/
class Cache extends Getters
@@ -31,10 +31,11 @@ class Cache extends Getters
protected $lifetime;
protected $now;
/** @var Config $config */
protected $config;
/**
* @var DoctrineCache
* @var DoctrineCache\CacheProvider
*/
protected $driver;
@@ -79,7 +80,7 @@ class Cache extends Getters
/**
* Constructor
*
* @params Grav $grav
* @param Grav $grav
*/
public function __construct(Grav $grav)
{
@@ -90,6 +91,7 @@ class Cache extends Getters
* Initialization that sets a base key and the driver based on configuration settings
*
* @param Grav $grav
*
* @return void
*/
public function init(Grav $grav)
@@ -105,10 +107,11 @@ class Cache extends Getters
$prefix = $this->config->get('system.cache.prefix');
$this->enabled = (bool) $this->config->get('system.cache.enabled');
$this->enabled = (bool)$this->config->get('system.cache.enabled');
// 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');
@@ -127,7 +130,7 @@ class Cache extends Getters
* If there is no config option for $driver in the config, or it's set to 'auto', it will
* pick the best option based on which cache extensions are installed.
*
* @return DoctrineCacheDriver The cache driver to use
* @return DoctrineCache\CacheProvider The cache driver to use
*/
public function getCacheDriver()
{
@@ -152,40 +155,40 @@ class Cache extends Getters
switch ($driver_name) {
case 'apc':
$driver = new \Doctrine\Common\Cache\ApcCache();
$driver = new DoctrineCache\ApcCache();
break;
case 'apcu':
$driver = new \Doctrine\Common\Cache\ApcuCache();
$driver = new DoctrineCache\ApcuCache();
break;
case 'wincache':
$driver = new \Doctrine\Common\Cache\WinCacheCache();
$driver = new DoctrineCache\WinCacheCache();
break;
case 'xcache':
$driver = new \Doctrine\Common\Cache\XcacheCache();
$driver = new DoctrineCache\XcacheCache();
break;
case 'memcache':
$memcache = new \Memcache();
$memcache->connect($this->config->get('system.cache.memcache.server','localhost'),
$this->config->get('system.cache.memcache.port', 11211));
$driver = new \Doctrine\Common\Cache\MemcacheCache();
$memcache->connect($this->config->get('system.cache.memcache.server', 'localhost'),
$this->config->get('system.cache.memcache.port', 11211));
$driver = new DoctrineCache\MemcacheCache();
$driver->setMemcache($memcache);
break;
case 'redis':
$redis = new \Redis();
$redis->connect($this->config->get('system.cache.redis.server','localhost'),
$this->config->get('system.cache.redis.port', 6379));
$redis->connect($this->config->get('system.cache.redis.server', 'localhost'),
$this->config->get('system.cache.redis.port', 6379));
$driver = new \Doctrine\Common\Cache\RedisCache();
$driver = new DoctrineCache\RedisCache();
$driver->setRedis($redis);
break;
default:
$driver = new \Doctrine\Common\Cache\FilesystemCache($this->cache_dir);
$driver = new DoctrineCache\FilesystemCache($this->cache_dir);
break;
}
@@ -196,6 +199,7 @@ class Cache extends Getters
* Gets a cached entry if it exists based on an id. If it does not exist, it returns false
*
* @param string $id the id of the cached entry
*
* @return object returns the cached entry, can be any type, or false if doesn't exist
*/
public function fetch($id)
@@ -210,9 +214,9 @@ class Cache extends Getters
/**
* Stores a new cached entry.
*
* @param string $id the id of the cached entry
* @param string $id the id of the cached entry
* @param array|object $data the data for the cached entry to store
* @param int $lifetime the lifetime to store the entry in seconds
* @param int $lifetime the lifetime to store the entry in seconds
*/
public function save($id, $data, $lifetime = null)
{
@@ -235,7 +239,7 @@ class Cache extends Getters
/**
* Helper method to clear all Grav caches
*
* @param string $remove standard|all|assets-only|images-only|cache-only
* @param string $remove standard|all|assets-only|images-only|cache-only
*
* @return array
*/
@@ -245,7 +249,7 @@ class Cache extends Getters
$output = [];
$user_config = USER_DIR . 'config/system.yaml';
switch($remove) {
switch ($remove) {
case 'all':
$remove_paths = self::$all_remove;
break;
@@ -268,8 +272,9 @@ class Cache extends Getters
// 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)
if (!$path) {
throw new \RuntimeException("Stream '{$stream}' not found", 500);
}
$anything = false;
$files = glob($path . '/*');

View File

@@ -35,6 +35,11 @@ class Composer
return $path;
}
/**
* Return the composer executable file path
*
* @return string
*/
public static function getComposerExecutor()
{
$executor = PHP_BINARY . ' ';

View File

@@ -158,7 +158,7 @@ class Setup extends Data
}
// Update streams.
foreach ($files as $path) {
foreach (array_reverse($files) as $path) {
$file = CompiledYamlFile::instance($path);
$content = $file->content();
if (!empty($content['schemes'])) {

View File

@@ -283,7 +283,7 @@ class Validation
protected static function filterFile($value, array $params, array $field)
{
if (isset($field['multiple']) && $field['multiple'] == true) {
if (isset($field['multiple']) && $field['multiple'] === true) {
return (array) $value;
}
@@ -559,6 +559,10 @@ class Validation
$options = isset($field['options']) ? array_keys($field['options']) : array();
$multi = isset($field['multiple']) ? $field['multiple'] : false;
if (count($values) == 1 && isset($values[0]) && $values[0] == '') {
return null;
}
if ($options) {
$useKey = isset($field['use']) && $field['use'] == 'keys';
foreach ($values as $key => $value) {

View File

@@ -1,8 +1,10 @@
<?php
namespace Grav\Common;
use DebugBar\DataCollector\ConfigCollector;
use DebugBar\JavascriptRenderer;
use DebugBar\StandardDebugBar;
use Grav\Common\Config\Config;
/**
* Class Debugger
@@ -10,45 +12,79 @@ use DebugBar\StandardDebugBar;
*/
class Debugger
{
/** @var Grav $grav */
protected $grav;
protected $debugbar;
/** @var Config $config */
protected $config;
/** @var JavascriptRenderer $renderer */
protected $renderer;
/** @var StandardDebugBar $debugbar */
protected $debugbar;
protected $enabled;
protected $timers = [];
/**
* Debugger constructor.
*/
public function __construct()
{
$this->debugbar = new StandardDebugBar();
$this->debugbar['time']->addMeasure('Loading', $this->debugbar['time']->getRequestStartTime(), microtime(true));
}
/**
* Initialize the debugger
*
* @return $this
* @throws \DebugBar\DebugBarException
*/
public function init()
{
$this->grav = Grav::instance();
$this->config = $this->grav['config'];
if ($this->enabled()) {
$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'));
$this->debugbar->addCollector(new ConfigCollector((array)$this->config->get('system'), 'Config'));
$this->debugbar->addCollector(new ConfigCollector((array)$this->config->get('plugins'), 'Plugins'));
}
return $this;
}
/**
* Set/get the enabled state of the debugger
*
* @param bool $state If null, the method returns the enabled value. If set, the method sets the enabled state
*
* @return null
*/
public function enabled($state = null)
{
if (isset($state)) {
$this->enabled = $state;
} else {
if (!isset($this->enabled)) {
$this->enabled = $this->grav['config']->get('system.debugger.enabled');
$this->enabled = $this->config->get('system.debugger.enabled');
}
}
return $this->enabled;
}
/**
* Add the debugger assets to the Grav Assets
*
* @return $this
*/
public function addAssets()
{
if ($this->enabled()) {
/** @var Assets $assets */
$assets = $this->grav['assets'];
// Add jquery library
@@ -69,58 +105,113 @@ class Debugger
$assets->addJs($js);
}
}
return $this;
}
/**
* Adds a data collector
*
* @param $collector
*
* @return $this
* @throws \DebugBar\DebugBarException
*/
public function addCollector($collector)
{
$this->debugbar->addCollector($collector);
return $this;
}
/**
* Returns a data collector
*
* @param $collector
*
* @return \DebugBar\DataCollector\DataCollectorInterface
* @throws \DebugBar\DebugBarException
*/
public function getCollector($collector)
{
return $this->debugbar->getCollector($collector);
}
/**
* Displays the debug bar
*
* @return $this
*/
public function render()
{
if ($this->enabled()) {
echo $this->renderer->render();
}
return $this;
}
/**
* Sends the data through the HTTP headers
*
* @return $this
*/
public function sendDataInHeaders()
{
$this->debugbar->sendDataInHeaders();
return $this;
}
/**
* Start a timer with an associated name and description
*
* @param $name
* @param string|null $description
*
* @return $this
*/
public function startTimer($name, $description = null)
{
if ($name[0] == '_' || $this->grav['config']->get('system.debugger.enabled')) {
if ($name[0] == '_' || $this->config->get('system.debugger.enabled')) {
$this->debugbar['time']->startMeasure($name, $description);
$this->timers[] = $name;
}
return $this;
}
/**
* Stop the named timer
*
* @param string $name
*
* @return $this
*/
public function stopTimer($name)
{
if (in_array($name, $this->timers) && ($name[0] == '_' || $this->grav['config']->get('system.debugger.enabled'))) {
if (in_array($name, $this->timers) && ($name[0] == '_' || $this->config->get('system.debugger.enabled'))) {
$this->debugbar['time']->stopMeasure($name);
}
return $this;
}
/**
* Dump variables into the Messages tab of the Debug Bar
*
* @param $message
* @param string $label
* @param bool $isString
*
* @return $this
*/
public function addMessage($message, $label = 'info', $isString = true)
{
if ($this->enabled()) {
$this->debugbar['messages']->addMessage($message, $label, $isString);
}
return $this;
}
}

View File

@@ -14,6 +14,7 @@ class Errors
{
$grav = Grav::instance();
$config = $grav['config']->get('system.errors');
$jsonRequest = $_SERVER && $_SERVER['HTTP_ACCEPT'] && $_SERVER['HTTP_ACCEPT'] == 'application/json';
// Setup Whoops-based error handler
$whoops = new \Whoops\Run;
@@ -30,11 +31,15 @@ class Errors
}
}
if (function_exists('Whoops\isAjaxRequest')) { //Whoops 2
if (Whoops\isAjaxRequest()) {
if (method_exists('Whoops\Util\Misc', 'isAjaxRequest')) { //Whoops 2.0
if (Whoops\Util\Misc::isAjaxRequest() || $jsonRequest) {
$whoops->pushHandler(new Whoops\Handler\JsonResponseHandler);
}
} else { //Whoops 1
} elseif (function_exists('Whoops\isAjaxRequest')) { //Whoops 2.0.0-alpha
if (Whoops\isAjaxRequest() || $jsonRequest) {
$whoops->pushHandler(new Whoops\Handler\JsonResponseHandler);
}
} else { //Whoops 1.x
$json_page = new Whoops\Handler\JsonResponseHandler;
$json_page->onlyForAjaxRequests(true);
}

View File

@@ -64,8 +64,9 @@ abstract class Folder
/**
* Get relative path between target and base path. If path isn't relative, return full path.
*
* @param string $path
* @param string $base
* @param string $path
* @param mixed|string $base
*
* @return string
*/
public static function getRelativePath($path, $base = GRAV_ROOT)
@@ -141,7 +142,7 @@ abstract class Folder
* @return array
* @throws \RuntimeException
*/
public static function all($path, array $params = array())
public static function all($path, array $params = [])
{
if ($path === false) {
throw new \RuntimeException("Path to {$path} doesn't exist.");
@@ -166,7 +167,7 @@ abstract class Folder
$iterator = new \FilesystemIterator($path);
}
$results = array();
$results = [];
/** @var \RecursiveDirectoryIterator $file */
foreach ($iterator as $file) {

View File

@@ -3,12 +3,21 @@ namespace Grav\Common\Filesystem;
use Grav\Common\GravTrait;
/**
* Class RecursiveFolderFilterIterator
* @package Grav\Common\Filesystem
*/
class RecursiveFolderFilterIterator extends \RecursiveFilterIterator
{
use GravTrait;
protected static $folder_ignores;
/**
* Create a RecursiveFilterIterator from a RecursiveIterator
*
* @param RecursiveIterator $iterator
*/
public function __construct(\RecursiveIterator $iterator)
{
parent::__construct($iterator);
@@ -17,9 +26,13 @@ class RecursiveFolderFilterIterator extends \RecursiveFilterIterator
}
}
/**
* Check whether the current element of the iterator is acceptable
*
* @return bool true if the current element is acceptable, otherwise false.
*/
public function accept()
{
/** @var $current \SplFileInfo */
$current = $this->current();

View File

@@ -121,6 +121,10 @@ class Installer
}
/**
* @param $state
* @param $install_path
*/
protected static function flightProcessing($state, $install_path)
{
$blueprints_path = $install_path . DS . 'blueprints.yaml';
@@ -140,6 +144,13 @@ class Installer
}
}
/**
* @param \ZipArchive $zip
* @param $install_path
* @param $tmp
*
* @return bool
*/
public static function moveInstall(\ZipArchive $zip, $install_path, $tmp)
{
$container = $zip->getNameIndex(0);
@@ -152,6 +163,13 @@ class Installer
return true;
}
/**
* @param \ZipArchive $zip
* @param $install_path
* @param $tmp
*
* @return bool
*/
public static function copyInstall(\ZipArchive $zip, $install_path, $tmp)
{
$firstDir = $zip->getNameIndex(0);
@@ -165,6 +183,13 @@ class Installer
return true;
}
/**
* @param \ZipArchive $zip
* @param $install_path
* @param $tmp
*
* @return bool
*/
public static function sophisticatedInstall(\ZipArchive $zip, $install_path, $tmp)
{
for ($i = 0, $l = $zip->numFiles; $i < $l; $i++) {
@@ -279,8 +304,6 @@ class Installer
*/
public static function lastErrorMsg()
{
$msg = 'Unknown Error';
if (is_string(self::$error)) {
return self::$error;
}
@@ -319,7 +342,7 @@ class Installer
break;
default:
return 'Unknown error';
$msg = 'Unknown Error';
break;
}

View File

@@ -2,9 +2,16 @@
namespace Grav\Common\GPM;
use Grav\Common\Utils;
use Grav\Common\GravTrait;
/**
* Class Response
* @package Grav\Common\GPM
*/
class Response
{
use GravTrait;
/**
* The callback for the progress
*
@@ -122,8 +129,7 @@ class Response
/**
* Progress normalized for cURL and Fopen
*
* @param args Variable length of arguments passed in by stream method
* Accepts a vsariable length of arguments passed in by stream method
*
* @return array Normalized array with useful data.
* Format: ['code' => int|false, 'filesize' => bytes, 'transferred' => bytes, 'percent' => int]
@@ -192,6 +198,12 @@ class Response
$options = $args[1];
$callback = $args[2];
// if proxy set add that
$proxy_url = self::getGrav()['config']->get('system.proxy_url');
if ($proxy_url) {
$options['fopen']['proxy'] = $proxy_url;
}
if ($callback) {
$options['fopen']['notification'] = ['self', 'progress'];
}
@@ -222,9 +234,10 @@ class Response
$ch = curl_init($uri);
$response = static::_curl_exec_follow($ch, $options, $callback);
$response = static::curlExecFollow($ch, $options, $callback);
$errno = curl_errno($ch);
if ($errno = curl_errno($ch)) {
if ($errno) {
$error_message = curl_strerror($errno);
throw new \RuntimeException("cURL error ({$errno}):\n {$error_message}");
}
@@ -234,7 +247,14 @@ class Response
return $response;
}
private static function _curl_exec_follow($ch, $options, $callback)
/**
* @param $ch
* @param $options
* @param $callback
*
* @return bool|mixed
*/
private static function curlExecFollow($ch, $options, $callback)
{
if ($callback) {
curl_setopt_array(
@@ -246,6 +266,12 @@ class Response
);
}
// if proxy set add that
$proxy_url = self::getGrav()['config']->get('system.proxy_url');
if ($proxy_url) {
$options['curl'][CURLOPT_PROXY] = $proxy_url;
}
// no open_basedir set, we can proceed normally
if (!ini_get('open_basedir')) {
curl_setopt_array($ch, $options['curl']);

View File

@@ -5,7 +5,7 @@ namespace Grav\Common;
* Abstract class to implement magic __get(), __set(), __isset() and __unset().
* Also implements ArrayAccess.
*
* @author RocketTheme
* @author RocketTheme
* @license MIT
*/
abstract class Getters implements \ArrayAccess, \Countable
@@ -32,6 +32,7 @@ abstract class Getters implements \ArrayAccess, \Countable
* Magic getter method
*
* @param mixed $offset Medium name value
*
* @return mixed Medium value
*/
public function __get($offset)
@@ -42,7 +43,8 @@ abstract class Getters implements \ArrayAccess, \Countable
/**
* Magic method to determine if the attribute is set
*
* @param mixed $offset Medium name value
* @param mixed $offset Medium name value
*
* @return boolean True if the value is set
*/
public function __isset($offset)
@@ -62,12 +64,14 @@ abstract class Getters implements \ArrayAccess, \Countable
/**
* @param mixed $offset
*
* @return bool
*/
public function offsetExists($offset)
{
if ($this->gettersVariable) {
$var = $this->gettersVariable;
return isset($this->{$var}[$offset]);
} else {
return isset($this->{$offset});
@@ -76,12 +80,14 @@ abstract class Getters implements \ArrayAccess, \Countable
/**
* @param mixed $offset
*
* @return mixed
*/
public function offsetGet($offset)
{
if ($this->gettersVariable) {
$var = $this->gettersVariable;
return isset($this->{$var}[$offset]) ? $this->{$var}[$offset] : null;
} else {
return isset($this->{$offset}) ? $this->{$offset} : null;
@@ -137,13 +143,17 @@ abstract class Getters implements \ArrayAccess, \Countable
{
if ($this->gettersVariable) {
$var = $this->gettersVariable;
return $this->{$var};
} else {
$properties = (array) $this;
$list = array();
$properties = (array)$this;
$list = [];
foreach ($properties as $property => $value) {
if ($property[0] != "\0") $list[$property] = $value;
if ($property[0] != "\0") {
$list[$property] = $value;
}
}
return $list;
}
}

View File

@@ -1,8 +1,11 @@
<?php
namespace Grav\Common;
use Grav\Common\Config\Config;
use Grav\Common\Language\Language;
use Grav\Common\Page\Medium\ImageMedium;
use Grav\Common\Page\Medium\Medium;
use Grav\Common\Page\Page;
use Grav\Common\Page\Pages;
use Grav\Common\Service\ConfigServiceProvider;
use Grav\Common\Service\ErrorServiceProvider;
@@ -16,8 +19,8 @@ use RocketTheme\Toolbox\Event\EventDispatcher;
/**
* Grav
*
* @author Andy Miller
* @link http://www.rockettheme.com
* @author Andy Miller
* @link http://www.rockettheme.com
* @license http://opensource.org/licenses/MIT
*
* Influenced by Pico, Stacey, Kirby, PieCrust and other great platforms...
@@ -34,7 +37,14 @@ class Grav extends Container
*/
protected static $instance;
public static function instance(array $values = array())
/**
* Return the Grav instance. Create it if it's not already instanced
*
* @param array $values
*
* @return Grav
*/
public static function instance(array $values = [])
{
if (!self::$instance) {
self::$instance = static::load($values);
@@ -51,6 +61,13 @@ class Grav extends Container
return self::$instance;
}
/**
* Initialize and return a Grav instance
*
* @param array $values
*
* @return static
*/
protected static function load(array $values)
{
$container = new static($values);
@@ -58,52 +75,63 @@ class Grav extends Container
$container['grav'] = $container;
$container['debugger'] = new Debugger();
$container['debugger']->startTimer('_init', 'Initialize');
$container['debugger']->startTimer('_services', 'Services');
$container->register(new LoggerServiceProvider);
$container->register(new ErrorServiceProvider);
$container['uri'] = function ($c) {
/** @var Grav $c */
return new Uri($c);
};
$container['task'] = function ($c) {
/** @var Grav $c */
return !empty($_POST['task']) ? $_POST['task'] : $c['uri']->param('task');
};
$container['events'] = function ($c) {
$container['events'] = function () {
return new EventDispatcher;
};
$container['cache'] = function ($c) {
/** @var Grav $c */
return new Cache($c);
};
$container['session'] = function ($c) {
/** @var Grav $c */
return new Session($c);
};
$container['plugins'] = function ($c) {
$container['plugins'] = function () {
return new Plugins();
};
$container['themes'] = function ($c) {
/** @var Grav $c */
return new Themes($c);
};
$container['twig'] = function ($c) {
/** @var Grav $c */
return new Twig($c);
};
$container['taxonomy'] = function ($c) {
/** @var Grav $c */
return new Taxonomy($c);
};
$container['language'] = function ($c) {
/** @var Grav $c */
return new Language($c);
};
$container['pages'] = function ($c) {
return new Page\Pages($c);
/** @var Grav $c */
return new Pages($c);
};
$container['assets'] = new Assets();
$container['page'] = function ($c) {
/** @var Grav $c */
/** @var Pages $pages */
$pages = $c['pages'];
/** @var Language $language */
@@ -138,7 +166,7 @@ class Grav extends Container
if (!$page || !$page->routable()) {
// Try fallback URL stuff...
$c->fallbackUrl($page, $path);
$c->fallbackUrl($path);
// If no page found, fire event
$event = $c->fireEvent('onPageNotFound');
@@ -149,23 +177,17 @@ class Grav extends Container
throw new \RuntimeException('Page Not Found', 404);
}
}
return $page;
};
$container['output'] = function ($c) {
/** @var Grav $c */
return $c['twig']->processSite($c['uri']->extension());
};
$container['browser'] = function ($c) {
return new Browser();
};
$container['base_url_absolute'] = function ($c) {
return $c['config']->get('system.base_url_absolute') ?: $c['uri']->rootUrl(true);
};
$container['base_url_relative'] = function ($c) {
return $c['config']->get('system.base_url_relative') ?: $c['uri']->rootUrl(false);
};
$container['base_url'] = function ($c) {
return $c['config']->get('system.absolute_urls') ? $c['base_url_absolute'] : $c['base_url_relative'];
$container['browser'] = function () {
return new Browser();
};
$container->register(new StreamsServiceProvider);
@@ -173,51 +195,64 @@ class Grav extends Container
$container['inflector'] = new Inflector();
$container['debugger']->stopTimer('_init');
$container['debugger']->stopTimer('_services');
return $container;
}
/**
* Process a request
*/
public function process()
{
/** @var Debugger $debugger */
$debugger = $this['debugger'];
// Load site setup and initializing streams.
$debugger->startTimer('_setup', 'Site Setup');
$this['setup']->init();
$this['streams'];
$debugger->stopTimer('_setup');
// Initialize configuration.
$debugger->startTimer('_config', 'Configuration');
$this['config']->init();
$this['errors']->resetHandlers();
$this['uri']->init();
$this['session']->init();
$debugger->init();
$this['config']->debug();
$debugger->stopTimer('_config');
// Initialize error handlers.
$this['errors']->resetHandlers();
// Initialize debugger.
$debugger->init();
$debugger->startTimer('init', 'Initialize');
$this['config']->debug();
// Use output buffering to prevent headers from being sent too early.
ob_start();
if ($this['config']->get('system.cache.gzip')) {
// Enable zip/deflate with a fallback in case of if browser does not support compressing.
if(!ob_start("ob_gzhandler")) {
if (!ob_start("ob_gzhandler")) {
ob_start();
}
}
// Initialize the timezone
// Initialize the timezone.
if ($this['config']->get('system.timezone')) {
date_default_timezone_set($this['config']->get('system.timezone'));
}
// Initialize Locale if set and configured
// Initialize uri, session.
$this['uri']->init();
$this['session']->init();
// Initialize Locale if set and configured.
if ($this['language']->enabled() && $this['config']->get('system.languages.override_locale')) {
setlocale(LC_ALL, $this['language']->getLanguage());
} elseif ($this['config']->get('system.default_locale')) {
setlocale(LC_ALL, $this['config']->get('system.default_locale'));
}
$debugger->startTimer('streams', 'Streams');
$this['streams'];
$debugger->stopTimer('streams');
$debugger->stopTimer('init');
$debugger->startTimer('plugins', 'Plugins');
$this['plugins']->init();
@@ -268,7 +303,7 @@ class Grav extends Container
* Redirect browser to another location.
*
* @param string $route Internal route.
* @param int $code Redirection code (30x)
* @param int $code Redirection code (30x)
*/
public function redirect($route, $code = null)
{
@@ -283,7 +318,7 @@ class Grav extends Container
$code = $matches[2];
}
if ($code == null) {
if ($code === null) {
$code = $this['config']->get('system.pages.redirect_default_code', 301);
}
@@ -294,10 +329,13 @@ class Grav extends Container
if ($uri->isExternal($route)) {
$url = $route;
} else {
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
$url = rtrim($uri->rootUrl(), '/') . '/';
if ($this['config']->get('system.pages.redirect_trailing_slash', true)) {
$url .= trim($route, '/'); // Remove trailing slash
} else {
$url .= ltrim($route, '/'); // Support trailing slash default routes
}
}
header("Location: {$url}", true, $code);
@@ -308,7 +346,7 @@ class Grav extends Container
* Redirect browser to another location taking language into account (preferred)
*
* @param string $route Internal route.
* @param int $code Redirection code (30x)
* @param int $code Redirection code (30x)
*/
public function redirectLangSafe($route, $code = null)
{
@@ -316,9 +354,9 @@ class Grav extends Container
$language = $this['language'];
if (!$this['uri']->isExternal($route) && $language->enabled() && $language->isIncludeDefaultLanguage()) {
return $this->redirect($language->getLanguage() . $route, $code);
$this->redirect($language->getLanguage() . $route, $code);
} else {
return $this->redirect($route, $code);
$this->redirect($route, $code);
}
}
@@ -326,6 +364,7 @@ class Grav extends Container
* Returns mime type for the file format.
*
* @param string $format
*
* @return string
*/
public function mime($format)
@@ -342,6 +381,7 @@ class Grav extends Container
case 'xml':
return 'application/xml';
}
return 'text/html';
}
@@ -363,7 +403,7 @@ class Grav extends Container
if ($expires > 0) {
$expires_date = gmdate('D, d M Y H:i:s', time() + $expires) . ' GMT';
header('Cache-Control: max-age=' . $expires);
header('Expires: '. $expires_date);
header('Expires: ' . $expires_date);
}
// Set the last modified time
@@ -398,12 +438,14 @@ class Grav extends Container
*
* @param string $eventName
* @param Event $event
*
* @return Event
*/
public function fireEvent($eventName, Event $event = null)
{
/** @var EventDispatcher $events */
$events = $this['events'];
return $events->dispatch($eventName, $event);
}
@@ -461,10 +503,10 @@ class Grav extends Container
/**
* This attempts to find media, other files, and download them
* @param $page
*
* @param $path
*/
protected function fallbackUrl($page, $path)
protected function fallbackUrl($path)
{
/** @var Uri $uri */
$uri = $this['uri'];
@@ -484,20 +526,22 @@ class Grav extends Container
}
$path_parts = pathinfo($path);
/** @var Page $page */
$page = $this['pages']->dispatch($path_parts['dirname'], true);
if ($page) {
$media = $page->media()->all();
$parsed_url = parse_url(rawurldecode($uri->basename()));
$media_file = $parsed_url['path'];
// if this is a media object, try actions first
if (isset($media[$media_file])) {
/** @var Medium $medium */
$medium = $media[$media_file];
foreach ($uri->query(null, true) as $action => $params) {
if (in_array($action, ImageMedium::$magic_actions)) {
call_user_func_array(array(&$medium, $action), explode(',', $params));
call_user_func_array([&$medium, $action], explode(',', $params));
}
}
Utils::download($medium->path(), false);

View File

@@ -1,6 +1,11 @@
<?php
namespace Grav\Common;
/**
* Class GravTrait
*
* @package Grav\Common
*/
trait GravTrait
{
/**
@@ -16,6 +21,7 @@ trait GravTrait
if (!self::$grav) {
self::$grav = Grav::instance();
}
return self::$grav;
}

View File

@@ -118,7 +118,7 @@ class Truncator {
list($txt, $nb, $opts) = static::truncateNode($doc, $childNode, $remaining, $opts);
}
else if ($childNode->nodeType === XML_TEXT_NODE) {
list($txt, $nb, $opts) = static::truncateText($doc, $childNode, $remaining, $opts);
list($txt, $nb, $opts) = static::truncateText($childNode, $remaining, $opts);
} else {
$txt = '';
$nb = 0;
@@ -141,7 +141,7 @@ class Truncator {
return array($inner, $remaining, $opts);
}
protected static function truncateText($doc, $node, $length, $opts)
protected static function truncateText($node, $length, $opts)
{
$string = $node->textContent;
@@ -165,7 +165,7 @@ class Truncator {
$words = $words[0];
$count = count($words);
if ($count <= $length && $length > 0) {
return array($xhtml, $count, $opts);
return array($string, $count, $opts);
}
return array(implode('', array_slice($words, 0, $length)), $count, $opts);
}

View File

@@ -4,20 +4,19 @@ namespace Grav\Common;
/**
* This file was originally part of the Akelos Framework
*/
use Grav\Common\Language\Language;
/**
* Inflector for pluralize and singularize English nouns.
*
* This Inflector is a port of Ruby on Rails Inflector.
*
* It can be really helpful for developers that want to
* create frameworks based on naming conventions rather than
* configurations.
*
* @author RocketTheme
* @license MIT
*/
* Inflector for pluralize and singularize English nouns.
*
* This Inflector is a port of Ruby on Rails Inflector.
*
* It can be really helpful for developers that want to
* create frameworks based on naming conventions rather than
* configurations.
*
* @author RocketTheme
* @license MIT
*/
class Inflector
{
@@ -42,11 +41,13 @@ class Inflector
}
/**
* Pluralizes English nouns.
*
* @param string $word English noun to pluralize
* @return string Plural noun
*/
* Pluralizes English nouns.
*
* @param string $word English noun to pluralize
* @param int $count The count
*
* @return string Plural noun
*/
public function pluralize($word, $count = 2)
{
$this->init();
@@ -58,14 +59,14 @@ class Inflector
$lowercased_word = strtolower($word);
foreach ($this->uncountable as $_uncountable) {
if (substr($lowercased_word, (-1*strlen($_uncountable))) == $_uncountable) {
if (substr($lowercased_word, (-1 * strlen($_uncountable))) == $_uncountable) {
return $word;
}
}
foreach ($this->irregular as $_plural => $_singular) {
if (preg_match('/('.$_plural.')$/i', $word, $arr)) {
return preg_replace('/('.$_plural.')$/i', substr($arr[0], 0, 1).substr($_singular, 1), $word);
if (preg_match('/(' . $_plural . ')$/i', $word, $arr)) {
return preg_replace('/(' . $_plural . ')$/i', substr($arr[0], 0, 1) . substr($_singular, 1), $word);
}
}
@@ -74,17 +75,19 @@ class Inflector
return preg_replace($rule, $replacement, $word);
}
}
return false;
}
/**
* Singularizes English nouns.
*
* @param string $word English noun to singularize
* @param int $count
* @return string Singular noun.
*/
* Singularizes English nouns.
*
* @param string $word English noun to singularize
* @param int $count
*
* @return string Singular noun.
*/
public function singularize($word, $count = 1)
{
$this->init();
@@ -95,14 +98,14 @@ class Inflector
$lowercased_word = strtolower($word);
foreach ($this->uncountable as $_uncountable) {
if (substr($lowercased_word, (-1*strlen($_uncountable))) == $_uncountable) {
if (substr($lowercased_word, (-1 * strlen($_uncountable))) == $_uncountable) {
return $word;
}
}
foreach ($this->irregular as $_plural => $_singular) {
if (preg_match('/('.$_singular.')$/i', $word, $arr)) {
return preg_replace('/('.$_singular.')$/i', substr($arr[0], 0, 1).substr($_plural, 1), $word);
if (preg_match('/(' . $_singular . ')$/i', $word, $arr)) {
return preg_replace('/(' . $_singular . ')$/i', substr($arr[0], 0, 1) . substr($_plural, 1), $word);
}
}
@@ -116,181 +119,206 @@ class Inflector
}
/**
* Converts an underscored or CamelCase word into a English
* sentence.
*
* The titleize public function converts text like "WelcomePage",
* "welcome_page" or "welcome page" to this "Welcome
* Page".
* If second parameter is set to 'first' it will only
* capitalize the first character of the title.
*
* @param string $word Word to format as tile
* @param string $uppercase If set to 'first' it will only uppercase the
* first character. Otherwise it will uppercase all
* the words in the title.
* @return string Text formatted as title
*/
* Converts an underscored or CamelCase word into a English
* sentence.
*
* The titleize public function converts text like "WelcomePage",
* "welcome_page" or "welcome page" to this "Welcome
* Page".
* If second parameter is set to 'first' it will only
* capitalize the first character of the title.
*
* @param string $word Word to format as tile
* @param string $uppercase If set to 'first' it will only uppercase the
* first character. Otherwise it will uppercase all
* the words in the title.
*
* @return string Text formatted as title
*/
public function titleize($word, $uppercase = '')
{
$uppercase = $uppercase == 'first' ? 'ucfirst' : 'ucwords';
return $uppercase($this->humanize($this->underscorize($word)));
}
/**
* Returns given word as CamelCased
*
* Converts a word like "send_email" to "SendEmail". It
* will remove non alphanumeric character from the word, so
* "who's online" will be converted to "WhoSOnline"
*
* @see variablize
* @param string $word Word to convert to camel case
* @return string UpperCamelCasedWord
*/
* Returns given word as CamelCased
*
* Converts a word like "send_email" to "SendEmail". It
* will remove non alphanumeric character from the word, so
* "who's online" will be converted to "WhoSOnline"
*
* @see variablize
*
* @param string $word Word to convert to camel case
*
* @return string UpperCamelCasedWord
*/
public function camelize($word)
{
return str_replace(' ', '', ucwords(preg_replace('/[^A-Z^a-z^0-9]+/', ' ', $word)));
}
/**
* Converts a word "into_it_s_underscored_version"
*
* Convert any "CamelCased" or "ordinary Word" into an
* "underscored_word".
*
* This can be really useful for creating friendly URLs.
*
* @param string $word Word to underscore
* @return string Underscored word
*/
* Converts a word "into_it_s_underscored_version"
*
* Convert any "CamelCased" or "ordinary Word" into an
* "underscored_word".
*
* This can be really useful for creating friendly URLs.
*
* @param string $word Word to underscore
*
* @return string Underscored word
*/
public function underscorize($word)
{
$regex1 = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1_\2', $word);
$regex2 = preg_replace('/([a-zd])([A-Z])/', '\1_\2', $regex1);
$regex3 = preg_replace('/[^A-Z^a-z^0-9]+/', '_', $regex2);
return strtolower($regex3);
return strtolower($regex3);
}
/**
* Converts a word "into-it-s-hyphenated-version"
*
* Convert any "CamelCased" or "ordinary Word" into an
* "hyphenated-word".
*
* This can be really useful for creating friendly URLs.
*
* @param string $word Word to hyphenate
* @return string hyphenized word
*/
* Converts a word "into-it-s-hyphenated-version"
*
* Convert any "CamelCased" or "ordinary Word" into an
* "hyphenated-word".
*
* This can be really useful for creating friendly URLs.
*
* @param string $word Word to hyphenate
*
* @return string hyphenized word
*/
public function hyphenize($word)
{
$regex1 = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1-\2', $word);
$regex2 = preg_replace('/([a-zd])([A-Z])/', '\1-\2', $regex1);
$regex3 = preg_replace('/[^A-Z^a-z^0-9]+/', '-', $regex2);
return strtolower($regex3);
return strtolower($regex3);
}
/**
* Returns a human-readable string from $word
*
* Returns a human-readable string from $word, by replacing
* underscores with a space, and by upper-casing the initial
* character by default.
*
* If you need to uppercase all the words you just have to
* pass 'all' as a second parameter.
*
* @param string $word String to "humanize"
* @param string $uppercase If set to 'all' it will uppercase all the words
* instead of just the first one.
* @return string Human-readable word
*/
* Returns a human-readable string from $word
*
* Returns a human-readable string from $word, by replacing
* underscores with a space, and by upper-casing the initial
* character by default.
*
* If you need to uppercase all the words you just have to
* pass 'all' as a second parameter.
*
* @param string $word String to "humanize"
* @param string $uppercase If set to 'all' it will uppercase all the words
* instead of just the first one.
*
* @return string Human-readable word
*/
public function humanize($word, $uppercase = '')
{
$uppercase = $uppercase == 'all' ? 'ucwords' : 'ucfirst';
return $uppercase(str_replace('_', ' ', preg_replace('/_id$/', '', $word)));
}
/**
* Same as camelize but first char is underscored
*
* Converts a word like "send_email" to "sendEmail". It
* will remove non alphanumeric character from the word, so
* "who's online" will be converted to "whoSOnline"
*
* @see camelize
* @param string $word Word to lowerCamelCase
* @return string Returns a lowerCamelCasedWord
*/
* Same as camelize but first char is underscored
*
* Converts a word like "send_email" to "sendEmail". It
* will remove non alphanumeric character from the word, so
* "who's online" will be converted to "whoSOnline"
*
* @see camelize
*
* @param string $word Word to lowerCamelCase
*
* @return string Returns a lowerCamelCasedWord
*/
public function variablize($word)
{
$word = $this->camelize($word);
return strtolower($word[0]).substr($word, 1);
return strtolower($word[0]) . substr($word, 1);
}
/**
* Converts a class name to its table name according to rails
* naming conventions.
*
* Converts "Person" to "people"
*
* @see classify
* @param string $class_name Class name for getting related table_name.
* @return string plural_table_name
*/
* Converts a class name to its table name according to rails
* naming conventions.
*
* Converts "Person" to "people"
*
* @see classify
*
* @param string $class_name Class name for getting related table_name.
*
* @return string plural_table_name
*/
public function tableize($class_name)
{
return $this->pluralize($this->underscore($class_name));
return $this->pluralize($this->underscorize($class_name));
}
/**
* Converts a table name to its class name according to rails
* naming conventions.
*
* Converts "people" to "Person"
*
* @see tableize
* @param string $table_name Table name for getting related ClassName.
* @return string SingularClassName
*/
* Converts a table name to its class name according to rails
* naming conventions.
*
* Converts "people" to "Person"
*
* @see tableize
*
* @param string $table_name Table name for getting related ClassName.
*
* @return string SingularClassName
*/
public function classify($table_name)
{
return $this->camelize($this->singularize($table_name));
}
/**
* Converts number to its ordinal English form.
*
* This method converts 13 to 13th, 2 to 2nd ...
*
* @param integer $number Number to get its ordinal value
* @return string Ordinal representation of given string.
*/
* Converts number to its ordinal English form.
*
* This method converts 13 to 13th, 2 to 2nd ...
*
* @param integer $number Number to get its ordinal value
*
* @return string Ordinal representation of given string.
*/
public function ordinalize($number)
{
$this->init();
if (in_array(($number % 100), range(11, 13))) {
return $number.$this->ordinals['default'];
return $number . $this->ordinals['default'];
} else {
switch (($number % 10)) {
case 1:
return $number.$this->ordinals['first'];
return $number . $this->ordinals['first'];
break;
case 2:
return $number.$this->ordinals['second'];
return $number . $this->ordinals['second'];
break;
case 3:
return $number.$this->ordinals['third'];
return $number . $this->ordinals['third'];
break;
default:
return $number.$this->ordinals['default'];
return $number . $this->ordinals['default'];
break;
}
}
}
/**
* Converts a number of days to a number of months
*
* @param int $days
*
* @return int
*/
public function monthize($days)
{
$now = new \DateTime();
@@ -300,9 +328,9 @@ class Inflector
$diff = $end->add($duration)->diff($now);
// handle years
// handle years
if ($diff->y > 0) {
$diff->m = $diff->m + 12*$diff->y;
$diff->m = $diff->m + 12 * $diff->y;
}
return $diff->m;

View File

@@ -26,6 +26,7 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
*
* @param string $key
* @param mixed $args
*
* @return mixed
*/
public function __call($key, $args)
@@ -79,11 +80,13 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
* Return nth item.
*
* @param int $key
*
* @return mixed|bool
*/
public function nth($key)
{
$items = array_keys($this->items);
return (isset($items[$key])) ? $this->offsetGet($items[$key]) : false;
}
@@ -95,6 +98,7 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
public function first()
{
$items = array_keys($this->items);
return $this->offsetGet(array_shift($items));
}
@@ -106,6 +110,7 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
public function last()
{
$items = array_keys($this->items);
return $this->offsetGet(array_pop($items));
}
@@ -117,11 +122,13 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
public function reverse()
{
$this->items = array_reverse($this->items);
return $this;
}
/**
* @param mixed $needle Searched value.
*
* @return string|bool Key if found, otherwise false.
*/
public function indexOf($needle)
@@ -131,6 +138,7 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
return $key;
}
}
return false;
}
@@ -144,7 +152,7 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
$keys = array_keys($this->items);
shuffle($keys);
$new = array();
$new = [];
foreach ($keys as $key) {
$new[$key] = $this->items[$key];
}
@@ -159,6 +167,7 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
*
* @param int $offset
* @param int $length
*
* @return $this
*/
public function slice($offset, $length = null)
@@ -171,12 +180,13 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
/**
* Pick one or more random entries.
*
* @param int $num Specifies how many entries should be picked.
* @param int $num Specifies how many entries should be picked.
*
* @return $this
*/
public function random($num = 1)
{
$this->items = array_intersect_key($this->items, array_flip((array) array_rand($this->items, $num)));
$this->items = array_intersect_key($this->items, array_flip((array)array_rand($this->items, $num)));
return $this;
}
@@ -184,7 +194,8 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
/**
* Append new elements to the list.
*
* @param array|Iterator $items Items to be appended. Existing keys will be overridden with the new values.
* @param array|Iterator $items Items to be appended. Existing keys will be overridden with the new values.
*
* @return $this
*/
public function append($items)
@@ -192,14 +203,17 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
if ($items instanceof static) {
$items = $items->toArray();
}
$this->items = array_merge($this->items, (array) $items);
$this->items = array_merge($this->items, (array)$items);
return $this;
}
/**
* Filter elements from the list
* @param callable|null $callback A function the receives ($value, $key) and must return a boolean to indicate filter status
*
* @param callable|null $callback A function the receives ($value, $key) and must return a boolean to indicate
* filter status
*
* @return $this
*/
public function filter(callable $callback = null)
@@ -207,7 +221,7 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
foreach ($this->items as $key => $value) {
if (
($callback && !call_user_func($callback, $value, $key)) ||
(!$callback && !(bool) $value)
(!$callback && !(bool)$value)
) {
unset($this->items[$key]);
}
@@ -230,7 +244,9 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
*/
public function sort(callable $callback = null, $desc = false)
{
if (!$callback || !is_callable($callback)) { return $this; }
if (!$callback || !is_callable($callback)) {
return $this;
}
$items = $this->items;
uasort($items, $callback);

View File

@@ -252,6 +252,8 @@ class Language
/**
* Gets an array of valid extensions with active first, then fallback extensions
*
* @param string|null $file_ext
*
* @return array
*/
public function getFallbackPageExtensions($file_ext = null)
@@ -328,15 +330,15 @@ class Language
/**
* Translate a key and possibly arguments into a string using current lang and fallbacks
*
* @param $args first argument is the lookup key value
* other arguments can be passed and replaced in the translation with sprintf syntax
* @param Array $languages
* @param mixed $args The first argument is the lookup key value
* Other arguments can be passed and replaced in the translation with sprintf syntax
* @param array $languages
* @param bool $array_support
* @param bool $html_out
*
* @return string
*/
public function translate($args, Array $languages = null, $array_support = false, $html_out = false)
public function translate($args, array $languages = null, $array_support = false, $html_out = false)
{
if (is_array($args)) {
$lookup = array_shift($args);
@@ -345,7 +347,6 @@ class Language
$args = [];
}
if ($this->config->get('system.languages.translations', true)) {
if ($this->enabled() && $lookup) {
if (empty($languages)) {
@@ -422,8 +423,8 @@ class Language
/**
* Lookup the translation text for a given lang and key
*
* @param $lang lang code
* @param $key key to lookup with
* @param string $lang lang code
* @param string $key key to lookup with
* @param bool $array_support
*
* @return string
@@ -438,6 +439,13 @@ class Language
return $translation;
}
/**
* Get the browser accepted languages
*
* @param array $accept_langs
*
* @return array
*/
public function getBrowserLanguages($accept_langs = [])
{
if (empty($this->http_accept_language)) {
@@ -451,9 +459,9 @@ class Language
// split $pref again by ';q='
// and decorate the language entries by inverted position
if (false !== ($i = strpos($pref, ';q='))) {
$langs[substr($pref, 0, $i)] = array((float)substr($pref, $i + 3), -$k);
$langs[substr($pref, 0, $i)] = [(float)substr($pref, $i + 3), -$k];
} else {
$langs[$pref] = array(1, -$k);
$langs[$pref] = [1, -$k];
}
}
arsort($langs);

View File

@@ -1,10 +1,20 @@
<?php
namespace Grav\Common\Markdown;
/**
* Class Parsedown
* @package Grav\Common\Markdown
*/
class Parsedown extends \Parsedown
{
use ParsedownGravTrait;
/**
* Parsedown constructor.
*
* @param $page
* @param $defaults
*/
public function __construct($page, $defaults)
{
$this->init($page, $defaults);

View File

@@ -1,10 +1,20 @@
<?php
namespace Grav\Common\Markdown;
/**
* Class ParsedownExtra
* @package Grav\Common\Markdown
*/
class ParsedownExtra extends \ParsedownExtra
{
use ParsedownGravTrait;
/**
* ParsedownExtra constructor.
*
* @param $page
* @param $defaults
*/
public function __construct($page, $defaults)
{
parent::__construct();

View File

@@ -2,6 +2,8 @@
namespace Grav\Common\Markdown;
use Grav\Common\GravTrait;
use Grav\Common\Page\Page;
use Grav\Common\Page\Pages;
use Grav\Common\Uri;
use RocketTheme\Toolbox\Event\Event;
@@ -11,12 +13,20 @@ use RocketTheme\Toolbox\Event\Event;
trait ParsedownGravTrait
{
use GravTrait;
/** @var Page $page */
protected $page;
/** @var Pages $pages */
protected $pages;
protected $base_url;
/** @var Uri $uri */
protected $uri;
protected $pages_dir;
protected $special_chars;
protected $twig_link_regex = '/\!*\[(?:.*)\]\((\{([\{%#])\s*(.*?)\s*(?:\2|\})\})\)/';
protected $special_protocols = ['xmpp', 'mailto', 'tel', 'sms'];
public $completable_blocks = [];
public $continuable_blocks = [];
@@ -33,10 +43,10 @@ trait ParsedownGravTrait
$this->page = $page;
$this->pages = $grav['pages'];
$this->uri = $grav['uri'];
$this->BlockTypes['{'] [] = "TwigTag";
$this->base_url = rtrim(self::getGrav()['base_url'] . self::getGrav()['pages']->base(), '/');
$this->pages_dir = self::getGrav()['locator']->findResource('page://');
$this->special_chars = array('>' => 'gt', '<' => 'lt', '"' => 'quot');
$this->special_chars = ['>' => 'gt', '<' => 'lt', '"' => 'quot'];
if ($defaults === null) {
$defaults = self::getGrav()['config']->get('system.pages.markdown');
@@ -59,7 +69,7 @@ trait ParsedownGravTrait
*/
public function addBlockType($type, $tag, $continuable = false, $completable = false)
{
$this->BlockTypes[$type] []= $tag;
$this->BlockTypes[$type] [] = $tag;
if ($continuable) {
$this->continuable_blocks[] = $tag;
@@ -78,7 +88,7 @@ trait ParsedownGravTrait
*/
public function addInlineType($type, $tag)
{
$this->InlineTypes[$type] []= $tag;
$this->InlineTypes[$type] [] = $tag;
$this->inlineMarkerList .= $type;
}
@@ -86,11 +96,13 @@ trait ParsedownGravTrait
* 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');
$continuable = in_array($Type, $this->continuable_blocks) || method_exists($this, 'block' . $Type . 'Continue');
return $continuable;
}
@@ -98,11 +110,13 @@ trait ParsedownGravTrait
* 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');
$completable = in_array($Type, $this->completable_blocks) || method_exists($this, 'block' . $Type . 'Complete');
return $completable;
}
@@ -110,7 +124,8 @@ trait ParsedownGravTrait
/**
* Make the element function publicly accessible, Medium uses this to render from Twig
*
* @param array $Element
* @param array $Element
*
* @return string markup
*/
public function elementToHtml(array $Element)
@@ -138,27 +153,28 @@ trait ParsedownGravTrait
protected function blockTwigTag($Line)
{
if (preg_match('/(?:{{|{%|{#)(.*)(?:}}|%}|#})/', $Line['body'], $matches)) {
$Block = array(
$Block = [
'markup' => $Line['body'],
);
];
return $Block;
}
}
protected function inlineSpecialCharacter($Excerpt)
{
if ($Excerpt['text'][0] === '&' && ! preg_match('/^&#?\w+;/', $Excerpt['text'])) {
return array(
if ($Excerpt['text'][0] === '&' && !preg_match('/^&#?\w+;/', $Excerpt['text'])) {
return [
'markup' => '&amp;',
'extent' => 1,
);
];
}
if (isset($this->special_chars[$Excerpt['text'][0]])) {
return array(
'markup' => '&'.$this->special_chars[$Excerpt['text'][0]].';',
return [
'markup' => '&' . $this->special_chars[$Excerpt['text'][0]] . ';',
'extent' => 1,
);
];
}
}
@@ -169,6 +185,7 @@ trait ParsedownGravTrait
$excerpt = parent::inlineImage($excerpt);
$excerpt['element']['attributes']['src'] = $matches[1];
$excerpt['extent'] = $excerpt['extent'] + strlen($matches[1]) - 1;
return $excerpt;
} else {
$excerpt['type'] = 'image';
@@ -176,7 +193,7 @@ trait ParsedownGravTrait
}
// Some stuff we will need
$actions = array();
$actions = [];
$media = null;
// if this is an image
@@ -188,23 +205,24 @@ trait ParsedownGravTrait
//get the url and parse it
$url = parse_url(htmlspecialchars_decode($excerpt['element']['attributes']['src']));
$this_host = isset($url['host']) && $url['host'] == $this->uri->host();
// if there is no host set but there is a path, the file is local
if (!isset($url['host']) && isset($url['path'])) {
if ((!isset($url['host']) || $this_host) && isset($url['path'])) {
$path_parts = pathinfo($url['path']);
// get the local path to page media if possible
if ($path_parts['dirname'] == $this->page->url(false, false, false)) {
$url['path'] = urldecode($path_parts['basename']);
// get the media objects for this page
$media = $this->page->media();
} else {
// see if this is an external page to this one
$page_route = str_replace($this->base_url, '', $path_parts['dirname']);
$base_url = rtrim(self::getGrav()['base_url_relative'] . self::getGrav()['pages']->base(), '/');
$page_route = '/' . ltrim(str_replace($base_url, '', $path_parts['dirname']), '/');
$ext_page = $this->pages->dispatch($page_route, true);
if ($ext_page) {
$media = $ext_page->media();
$url['path'] = urldecode($path_parts['basename']);
}
}
@@ -218,7 +236,7 @@ trait ParsedownGravTrait
$actions = array_reduce(explode('&', $url['query']), function ($carry, $item) {
$parts = explode('=', $item, 2);
$value = isset($parts[1]) ? $parts[1] : null;
$carry[] = [ 'method' => $parts[0], 'params' => $value ];
$carry[] = ['method' => $parts[0], 'params' => $value];
return $carry;
}, []);
@@ -226,14 +244,15 @@ trait ParsedownGravTrait
// loop through actions for the image and call them
foreach ($actions as $action) {
$medium = call_user_func_array(array($medium, $action['method']), explode(',', urldecode($action['params'])));
$medium = call_user_func_array([$medium, $action['method']],
explode(',', urldecode($action['params'])));
}
if (isset($url['fragment'])) {
$medium->urlHash($url['fragment']);
}
$excerpt['element'] = $medium->parseDownElement($title, $alt, $class);
$excerpt['element'] = $medium->parseDownElement($title, $alt, $class, true);
} else {
// not a current page media file, see if it needs converting to relative
@@ -259,6 +278,7 @@ trait ParsedownGravTrait
$excerpt = parent::inlineLink($excerpt);
$excerpt['element']['attributes']['href'] = $matches[1];
$excerpt['extent'] = $excerpt['extent'] + strlen($matches[1]) - 1;
return $excerpt;
} else {
$excerpt = parent::inlineLink($excerpt);
@@ -300,8 +320,7 @@ trait ParsedownGravTrait
}
}
$url['query']= http_build_query($actions, null, '&', PHP_QUERY_RFC3986);
$url['query'] = http_build_query($actions, null, '&', PHP_QUERY_RFC3986);
}
// if no query elements left, unset query
@@ -309,12 +328,21 @@ trait ParsedownGravTrait
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)) {
$excerpt['element']['attributes']['href'] = Uri::convertUrl($this->page, Uri::buildUrl($url), $type, true);
} else {
$excerpt['element']['attributes']['href'] = Uri::buildUrl($url);
// set path to / if not set
if (empty($url['path'])) {
$url['path'] = '';
}
// if special scheme, just return
if(isset($url['scheme']) && in_array($url['scheme'], $this->special_protocols)) {
return $excerpt;
}
// handle paths and such
$url = Uri::convertUrl($this->page, $url, $type);
// build the URL from the component parts and set it on the element
$excerpt['element']['attributes']['href'] = Uri::buildUrl($url);
}
return $excerpt;
@@ -325,6 +353,7 @@ trait ParsedownGravTrait
{
if (isset($this->$method) === true) {
$func = $this->$method;
return call_user_func_array($func, $args);
}
}

View File

@@ -8,7 +8,7 @@ use Grav\Common\Utils;
/**
* Collection of Pages.
*
* @author RocketTheme
* @author RocketTheme
* @license MIT
*/
class Collection extends Iterator
@@ -23,7 +23,14 @@ class Collection extends Iterator
*/
protected $params;
public function __construct($items = array(), array $params = array(), Pages $pages = null)
/**
* Collection constructor.
*
* @param array $items
* @param array $params
* @param Pages|null $pages
*/
public function __construct($items = [], array $params = [], Pages $pages = null)
{
parent::__construct($items);
@@ -31,6 +38,11 @@ class Collection extends Iterator
$this->pages = $pages ? $pages : Grav::instance()->offsetGet('pages');
}
/**
* Get the collection params
*
* @return array
*/
public function params()
{
return $this->params;
@@ -40,11 +52,13 @@ class Collection extends Iterator
* Add a single page to a collection
*
* @param Page $page
*
* @return $this
*/
public function addPage(Page $page)
{
$this->items[$page->path()] = ['slug' => $page->slug()];
return $this;
}
@@ -63,11 +77,13 @@ class Collection extends Iterator
* Set parameters to the Collection
*
* @param array $params
*
* @return $this
*/
public function setParams(array $params)
{
$this->params = array_merge($this->params, $params);
return $this;
}
@@ -79,6 +95,7 @@ class Collection extends Iterator
public function current()
{
$current = parent::key();
return $this->pages->get($current);
}
@@ -90,13 +107,15 @@ class Collection extends Iterator
public function key()
{
$current = parent::current();
return $current['slug'];
}
/**
* Returns the value at specified offset.
*
* @param mixed $offset The offset to retrieve.
* @param mixed $offset The offset to retrieve.
*
* @return mixed Can return all value types.
*/
public function offsetGet($offset)
@@ -108,6 +127,7 @@ class Collection extends Iterator
* Remove item from the list.
*
* @param Page|string|null $key
*
* @return $this|void
* @throws \InvalidArgumentException
*/
@@ -123,6 +143,7 @@ class Collection extends Iterator
}
parent::remove($key);
return $this;
}
@@ -132,6 +153,7 @@ class Collection extends Iterator
* @param string $by
* @param string $dir
* @param array $manual
*
* @return $this
*/
public function order($by, $dir = 'asc', $manual = null)
@@ -145,6 +167,7 @@ class Collection extends Iterator
* Check to see if this item is the first in the collection.
*
* @param string $path
*
* @return boolean True if item is first.
*/
public function isFirst($path)
@@ -160,11 +183,12 @@ class Collection extends Iterator
* Check to see if this item is the last in the collection.
*
* @param string $path
*
* @return boolean True if item is last.
*/
public function isLast($path)
{
if ($this->items && $path == array_keys($this->items)[count($this->items)-1]) {
if ($this->items && $path == array_keys($this->items)[count($this->items) - 1]) {
return true;
} else {
return false;
@@ -174,7 +198,8 @@ class Collection extends Iterator
/**
* Gets the previous sibling based on current position.
*
* @param string $path
* @param string $path
*
* @return Page The previous item.
*/
public function prevSibling($path)
@@ -185,7 +210,8 @@ class Collection extends Iterator
/**
* Gets the next sibling based on current position.
*
* @param string $path
* @param string $path
*
* @return Page The next item.
*/
public function nextSibling($path)
@@ -198,6 +224,7 @@ class Collection extends Iterator
*
* @param string $path
* @param integer $direction either -1 or +1
*
* @return Page The sibling item.
*/
public function adjacentSibling($path, $direction = 1)
@@ -210,6 +237,7 @@ class Collection extends Iterator
return isset($values[$index]) ? $this->offsetGet($values[$index]) : $this;
}
return $this;
}
@@ -217,7 +245,8 @@ class Collection extends Iterator
/**
* Returns the item in the current position.
*
* @param string $path the path the item
* @param string $path the path the item
*
* @return Page Item in the array the the current position.
*/
public function currentPosition($path)
@@ -256,6 +285,7 @@ class Collection extends Iterator
}
}
$this->items = $date_range;
return $this;
}
@@ -275,6 +305,7 @@ class Collection extends Iterator
}
}
$this->items = $visible;
return $this;
}
@@ -294,6 +325,7 @@ class Collection extends Iterator
}
}
$this->items = $visible;
return $this;
}
@@ -313,6 +345,7 @@ class Collection extends Iterator
}
}
$this->items = $modular;
return $this;
}
@@ -332,6 +365,7 @@ class Collection extends Iterator
}
}
$this->items = $modular;
return $this;
}
@@ -351,6 +385,7 @@ class Collection extends Iterator
}
}
$this->items = $published;
return $this;
}
@@ -370,6 +405,7 @@ class Collection extends Iterator
}
}
$this->items = $published;
return $this;
}
@@ -391,6 +427,7 @@ class Collection extends Iterator
}
$this->items = $routable;
return $this;
}
@@ -410,12 +447,15 @@ class Collection extends Iterator
}
}
$this->items = $routable;
return $this;
}
/**
* Creates new collection with only pages of the specified type
*
* @param $type
*
* @return Collection The collection
*/
public function ofType($type)
@@ -430,12 +470,15 @@ class Collection extends Iterator
}
$this->items = $items;
return $this;
}
/**
* Creates new collection with only pages of one of the specified types
*
* @param $types
*
* @return Collection The collection
*/
public function ofOneOfTheseTypes($types)
@@ -450,12 +493,15 @@ class Collection extends Iterator
}
$this->items = $items;
return $this;
}
/**
* Creates new collection with only pages of one of the specified access levels
*
* @param $accessLevels
*
* @return Collection The collection
*/
public function ofOneOfTheseAccessLevels($accessLevels)
@@ -472,7 +518,7 @@ class Collection extends Iterator
foreach ($page->header()->access as $index => $accessLevel) {
if (is_array($accessLevel)) {
foreach($accessLevel as $innerIndex => $innerAccessLevel) {
foreach ($accessLevel as $innerIndex => $innerAccessLevel) {
if (in_array($innerAccessLevel, $accessLevels)) {
$valid = true;
}
@@ -497,11 +543,7 @@ class Collection extends Iterator
}
$this->items = $items;
return $this;
}
}

View File

@@ -5,6 +5,10 @@ namespace Grav\Common\Page;
use RocketTheme\Toolbox\ArrayTraits\Constructor;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccess;
/**
* Class Header
* @package Grav\Common\Page
*/
class Header implements \ArrayAccess
{
use NestedArrayAccess, Constructor;

View File

@@ -20,11 +20,11 @@ class Media extends Getters
protected $gettersVariable = 'instances';
protected $path;
protected $instances = array();
protected $images = array();
protected $videos = array();
protected $audios = array();
protected $files = array();
protected $instances = [];
protected $images = [];
protected $videos = [];
protected $audios = [];
protected $files = [];
/**
* @param $path

View File

@@ -1,6 +1,7 @@
<?php
namespace Grav\Common\Page\Medium;
use Grav\Common\Utils;
use Grav\Common\Data\Blueprint;
class ImageMedium extends Medium
@@ -136,7 +137,15 @@ class ImageMedium extends Medium
*/
public function url($reset = true)
{
$output = preg_replace('|^' . preg_quote(GRAV_ROOT) . '|', '', $this->saveImage());
$image_path = self::$grav['locator']->findResource('cache://images', true);
$image_dir = self::$grav['locator']->findResource('cache://images', false);
$saved_image_path = $this->saveImage();
$output = preg_replace('|^' . preg_quote(GRAV_ROOT) . '|', '', $saved_image_path);
if (Utils::startsWith($output, $image_path)) {
$output = '/' . $image_dir . preg_replace('|^' . preg_quote($image_path) . '|', '', $output);
}
if ($reset) {
$this->reset();
@@ -155,6 +164,7 @@ class ImageMedium extends Medium
if (!$this->image) {
$this->image();
}
return $this;
}
@@ -261,6 +271,7 @@ class ImageMedium extends Medium
if ($this->image) {
$this->image();
$this->image->clearOperations(); // Clear previously applied operations
$this->querystring('');
$this->filter();
}

View File

@@ -118,7 +118,7 @@ class Medium extends Data implements RenderableInterface
* Return PATH to file.
*
* @param bool $reset
* @return string path to file
* @return string path to file
*/
public function path($reset = true)
{
@@ -155,7 +155,7 @@ class Medium extends Data implements RenderableInterface
*/
public function querystring($querystring = null, $withQuestionmark = true)
{
if ($querystring) {
if (!is_null($querystring)) {
$this->set('querystring', ltrim($querystring, '?&'));
foreach ($this->alternatives as $alt) {

File diff suppressed because it is too large Load Diff

View File

@@ -1,24 +1,24 @@
<?php
namespace Grav\Common\Page;
use Grav\Common\Grav;
use Grav\Common\Config\Config;
use Grav\Common\Utils;
use Grav\Common\Cache;
use Grav\Common\Taxonomy;
use Grav\Common\Language;
use Grav\Common\Config\Config;
use Grav\Common\Data\Blueprint;
use Grav\Common\Data\Blueprints;
use Grav\Common\Filesystem\Folder;
use Grav\Common\Grav;
use Grav\Common\Language\Language;
use Grav\Common\Taxonomy;
use Grav\Common\Utils;
use Grav\Plugin\Admin;
use RocketTheme\Toolbox\Event\Event;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use Whoops\Exception\ErrorException;
/**
* GravPages is the class that is the entry point into the hierarchy of pages
* Pages is the class that is the entry point into the hierarchy of pages
*
* @author RocketTheme
* @author RocketTheme
* @license MIT
*/
class Pages
@@ -46,7 +46,7 @@ class Pages
/**
* @var array|string[]
*/
protected $routes = array();
protected $routes = [];
/**
* @var array
@@ -63,8 +63,19 @@ class Pages
*/
protected $last_modified;
/**
* @var array|string[]
*/
protected $ignore_files;
/**
* @var array|string[]
*/
protected $ignore_folders;
/**
* @var bool
*/
protected $ignore_hidden;
/**
@@ -72,6 +83,9 @@ class Pages
*/
static protected $types;
/**
* @var string
*/
static protected $home_route;
/**
@@ -89,6 +103,7 @@ class Pages
* Get or set base path for the pages.
*
* @param string $path
*
* @return string
*/
public function base($path = null)
@@ -111,6 +126,10 @@ class Pages
$this->ignore_folders = $config->get('system.pages.ignore_folders');
$this->ignore_hidden = $config->get('system.pages.ignore_hidden');
$this->instances = [];
$this->children = [];
$this->routes = [];
$this->buildPages();
}
@@ -118,6 +137,7 @@ class Pages
* Get or set last modification time.
*
* @param int $modified
*
* @return int|null
*/
public function lastModified($modified = null)
@@ -125,6 +145,7 @@ class Pages
if ($modified && $modified > $this->last_modified) {
$this->last_modified = $modified;
}
return $this->last_modified;
}
@@ -151,8 +172,8 @@ class Pages
/**
* Adds a page and assigns a route to it.
*
* @param Page $page Page to be added.
* @param string $route Optional route (uses route from the object if not set).
* @param Page $page Page to be added.
* @param string $route Optional route (uses route from the object if not set).
*/
public function addPage(Page $page, $route = null)
{
@@ -161,7 +182,7 @@ class Pages
}
$route = $page->route($route);
if ($page->parent()) {
$this->children[$page->parent()->path()][$page->path()] = array('slug' => $page->slug());
$this->children[$page->parent()->path()][$page->path()] = ['slug' => $page->slug()];
}
$this->routes[$route] = $page->path();
}
@@ -169,7 +190,7 @@ class Pages
/**
* Sort sub-pages in a page.
*
* @param Page $page
* @param Page $page
* @param string $order_by
* @param string $order_dir
*
@@ -185,7 +206,7 @@ class Pages
}
$path = $page->path();
$children = isset($this->children[$path]) ? $this->children[$path] : array();
$children = isset($this->children[$path]) ? $this->children[$path] : [];
if (!$children) {
return $children;
@@ -206,9 +227,10 @@ class Pages
/**
* @param Collection $collection
* @param $orderBy
* @param string $orderDir
* @param null $orderManual
* @param $orderBy
* @param string $orderDir
* @param null $orderManual
*
* @return array
* @internal
*/
@@ -219,7 +241,7 @@ class Pages
return [];
}
$lookup = md5(json_encode($items));
$lookup = md5(json_encode($items) . json_encode($orderManual) . $orderBy . $orderDir);
if (!isset($this->sort[$lookup][$orderBy])) {
$this->buildSort($lookup, $items, $orderBy, $orderManual);
}
@@ -237,7 +259,8 @@ class Pages
/**
* Get a page instance.
*
* @param string $path The filesystem full path of the page
* @param string $path The filesystem full path of the page
*
* @return Page
* @throws \Exception
*/
@@ -246,26 +269,30 @@ class Pages
if (!is_null($path) && !is_string($path)) {
throw new \Exception();
}
return isset($this->instances[(string) $path]) ? $this->instances[(string) $path] : null;
return isset($this->instances[(string)$path]) ? $this->instances[(string)$path] : null;
}
/**
* Get children of the path.
*
* @param string $path
*
* @return Collection
*/
public function children($path)
{
$children = isset($this->children[(string) $path]) ? $this->children[(string) $path] : array();
return new Collection($children, array(), $this);
$children = isset($this->children[(string)$path]) ? $this->children[(string)$path] : [];
return new Collection($children, [], $this);
}
/**
* Dispatch URI to a page.
*
* @param string $url The relative URL of the page
* @param bool $all
* @param bool $all
*
* @return Page|null
*/
public function dispatch($url, $all = false)
@@ -297,28 +324,34 @@ class Pages
$page = $this->dispatch($route, $all);
} else {
// Try Regex style redirects
foreach ((array)$config->get("site.redirects") as $pattern => $replace) {
$pattern = '#' . $pattern . '#';
try {
$found = preg_replace($pattern, $replace, $url);
if ($found != $url) {
$this->grav->redirectLangSafe($found);
$site_redirects = $config->get("site.redirects");
if (is_array($site_redirects)) {
foreach ((array)$site_redirects as $pattern => $replace) {
$pattern = '#' . $pattern . '#';
try {
$found = preg_replace($pattern, $replace, $url);
if ($found != $url) {
$this->grav->redirectLangSafe($found);
}
} catch (ErrorException $e) {
$this->grav['log']->error('site.redirects: ' . $pattern . '-> ' . $e->getMessage());
}
} catch (ErrorException $e) {
$this->grav['log']->error('site.redirects: ' . $pattern . '-> ' . $e->getMessage());
}
}
// Try Regex style routes
foreach ((array)$config->get("site.routes") as $pattern => $replace) {
$pattern = '#' . $pattern . '#';
try {
$found = preg_replace($pattern, $replace, $url);
if ($found != $url) {
$page = $this->dispatch($found, $all);
$site_routes = $config->get("site.routes");
if (is_array($site_routes)) {
foreach ((array)$site_routes as $pattern => $replace) {
$pattern = '#' . $pattern . '#';
try {
$found = preg_replace($pattern, $replace, $url);
if ($found != $url) {
$page = $this->dispatch($found, $all);
}
} catch (ErrorException $e) {
$this->grav['log']->error('site.routes: ' . $pattern . '-> ' . $e->getMessage());
}
} catch (ErrorException $e) {
$this->grav['log']->error('site.routes: '. $pattern . '-> ' . $e->getMessage());
}
}
}
@@ -336,14 +369,14 @@ class Pages
{
/** @var UniformResourceLocator $locator */
$locator = $this->grav['locator'];
return $this->instances[rtrim($locator->findResource('page://'), DS)];
}
/**
* Get a blueprint for a page type.
*
* @param string $type
* @param string $type
*
* @return Blueprint
*/
public function blueprints($type)
@@ -370,6 +403,7 @@ class Pages
* Get all pages
*
* @param \Grav\Common\Page\Page $current
*
* @return \Grav\Common\Page\Collection
*/
public function all(Page $current = null)
@@ -380,7 +414,7 @@ class Pages
$current = $current ?: $this->root();
if (!$current->root()) {
$all[$current->path()] = [ 'slug' => $current->slug() ];
$all[$current->path()] = ['slug' => $current->slug()];
}
foreach ($current->children() as $next) {
@@ -394,11 +428,14 @@ class Pages
* Get list of route/title of all pages.
*
* @param Page $current
* @param int $level
* @param int $level
* @param bool $rawRoutes
*
* @return array
*
* @throws \RuntimeException
*/
public function getList(Page $current = null, $level = 0)
public function getList(Page $current = null, $level = 0, $rawRoutes = false)
{
if (!$current) {
if ($level) {
@@ -408,14 +445,19 @@ class Pages
$current = $this->root();
}
$list = array();
$list = [];
if (!$current->root()) {
$list[$current->route()] = str_repeat('&nbsp; ', ($level-1)*2) . $current->title();
if ($rawRoutes) {
$route = $current->rawRoute();
} else {
$route = $current->route();
}
$list[$route] = str_repeat('&nbsp; ', ($level - 1) * 2) . $current->title();
}
foreach ($current->children() as $next) {
$list = array_merge($list, $this->getList($next, $level + 1));
$list = array_merge($list, $this->getList($next, $level + 1, $rawRoutes));
}
return $list;
@@ -494,12 +536,12 @@ class Pages
public function accessLevels()
{
$accessLevels = [];
foreach($this->all() as $page) {
foreach ($this->all() as $page) {
if (isset($page->header()->access)) {
if (is_array($page->header()->access)) {
foreach($page->header()->access as $index => $accessLevel) {
foreach ($page->header()->access as $index => $accessLevel) {
if (is_array($accessLevel)) {
foreach($accessLevel as $innerIndex => $innerAccessLevel) {
foreach ($accessLevel as $innerIndex => $innerAccessLevel) {
array_push($accessLevels, $innerIndex);
}
} else {
@@ -517,18 +559,44 @@ class Pages
}
/**
* Get available parents.
* Get available parents routes
*
* @return array
*/
public static function parents()
{
$rawRoutes = false;
return self::getParents($rawRoutes);
}
/**
* Get available parents raw routes.
*
* @return array
*/
public static function parentsRawRoutes()
{
$rawRoutes = true;
return self::getParents($rawRoutes);
}
/**
* Get available parents routes
*
* @param bool $rawRoutes get the raw route or the normal route
*
* @return array
*/
private static function getParents($rawRoutes)
{
$grav = Grav::instance();
/** @var Pages $pages */
$pages = $grav['pages'];
$parents = $pages->getList();
$parents = $pages->getList(null, 0, $rawRoutes);
/** @var Admin $admin */
$admin = $grav['admin'];
@@ -547,13 +615,13 @@ class Pages
}
/**
* Get's the home route
* Gets the home route
*
* @return string
*/
public static function getHomeRoute()
{
if (empty(self::$home)) {
if (empty(self::$home_route)) {
$grav = Grav::instance();
/** @var Config $config */
@@ -585,9 +653,19 @@ class Pages
self::$home_route = trim($home, '/');
}
return self::$home_route;
}
/**
* Needed for testing where we change the home route via config
*/
public static function resetHomeRoute()
{
self::$home_route = null;
return self::getHomeRoute();
}
/**
* Builds pages.
*
@@ -595,7 +673,7 @@ class Pages
*/
protected function buildPages()
{
$this->sort = array();
$this->sort = [];
/** @var Config $config */
$config = $this->grav['config'];
@@ -626,7 +704,7 @@ class Pages
$last_modified = Folder::lastModifiedFile($pages_dir);
}
$page_cache_id = md5(USER_DIR.$last_modified.$language->getActive().$config->checksum());
$page_cache_id = md5(USER_DIR . $last_modified . $language->getActive() . $config->checksum());
list($this->instances, $this->routes, $this->children, $taxonomy_map, $this->sort) = $cache->fetch($page_cache_id);
if (!$this->instances) {
@@ -659,35 +737,33 @@ class Pages
// cache if needed
if ($this->grav['config']->get('system.cache.enabled')) {
/** @var Cache $cache */
/** @var Cache $cache */
$cache = $this->grav['cache'];
/** @var Taxonomy $taxonomy */
$taxonomy = $this->grav['taxonomy'];
// save pages, routes, taxonomy, and sort to cache
$cache->save(
$page_cache_id,
array($this->instances, $this->routes, $this->children, $taxonomy->taxonomy(), $this->sort)
);
$cache->save($page_cache_id, [$this->instances, $this->routes, $this->children, $taxonomy->taxonomy(), $this->sort]);
}
}
/**
* Recursive function to load & build page relationships.
*
* @param string $directory
* @param string $directory
* @param Page|null $parent
*
* @return Page
* @throws \RuntimeException
* @internal
*/
protected function recurse($directory, Page &$parent = null)
{
$directory = rtrim($directory, DS);
$page = new Page;
$directory = rtrim($directory, DS);
$page = new Page;
/** @var Config $config */
$config = $this->grav['config'];
$config = $this->grav['config'];
/** @var Language $language */
$language = $this->grav['language'];
@@ -713,20 +789,21 @@ class Pages
if (!isset($this->instances[$page->path()])) {
$this->instances[$page->path()] = $page;
if ($parent && $page->path()) {
$this->children[$parent->path()][$page->path()] = array('slug' => $page->slug());
$this->children[$parent->path()][$page->path()] = ['slug' => $page->slug()];
}
} else {
throw new \RuntimeException('Fatal error when creating page instances.');
}
$content_exists = false;
$pages_found = glob($directory.'/*'.CONTENT_EXT);
$page_extensions = $language->getFallbackPageExtensions();
$pages_found = glob($directory . '/*' . CONTENT_EXT);
$page_extension = '';
if ($pages_found) {
$page_extensions = $language->getFallbackPageExtensions();
foreach ($page_extensions as $extension) {
foreach ($pages_found as $found) {
if (preg_match('/^.*\/[0-9A-Za-z\-\_]+('.$extension.')$/', $found)) {
if (preg_match('/^.*\/[0-9A-Za-z\-\_]+(' . $extension . ')$/', $found)) {
$page_found = $found;
$page_extension = $extension;
break 2;
@@ -770,14 +847,14 @@ class Pages
$page->path($file->getPath());
}
$path = $directory.DS.$name;
$path = $directory . DS . $name;
$child = $this->recurse($path, $page);
if (Utils::startsWith($name, '_')) {
$child->routable(false);
}
$this->children[$page->path()][$child->path()] = array('slug' => $child->slug());
$this->children[$page->path()][$child->path()] = ['slug' => $child->slug()];
if ($config->get('system.pages.events.page')) {
$this->grav->fireEvent('onFolderProcessed', new Event(['page' => $page]));
@@ -790,9 +867,20 @@ class Pages
$page->routable(false);
}
// Override the modified time if modular
if ($page->template() == 'modular') {
foreach ($page->collection() as $child) {
$modified = $child->modified();
if ($modified > $last_modified) {
$last_modified = $modified;
}
}
}
// Override the modified and ID so that it takes the latest change into account
$page->modified($last_modified);
$page->id($last_modified.md5($page->filePath()));
$page->id($last_modified . md5($page->filePath()));
// Sort based on Defaults or Page Overridden sort order
$this->children[$page->path()] = $this->sort($page);
@@ -809,7 +897,7 @@ class Pages
$taxonomy = $this->grav['taxonomy'];
// Get the home route
$home = self::getHomeRoute();
$home = self::resetHomeRoute();
// Build routes and taxonomy map.
/** @var $page Page */
@@ -818,7 +906,7 @@ class Pages
// process taxonomy
$taxonomy->addTaxonomy($page);
$route = $page->route();
$route = $page->route();
$raw_route = $page->rawRoute();
$page_path = $page->path();
@@ -855,19 +943,20 @@ class Pages
/**
* @param string $path
* @param array $pages
* @param array $pages
* @param string $order_by
* @param array $manual
* @param array $manual
*
* @throws \RuntimeException
* @internal
*/
protected function buildSort($path, array $pages, $order_by = 'default', $manual = null)
{
$list = array();
$list = [];
$header_default = null;
$header_query = null;
// do this headery query work only once
// do this header query work only once
if (strpos($order_by, 'header.') === 0) {
$header_query = explode('|', str_replace('header.', '', $order_by));
if (isset($header_query[1])) {
@@ -924,7 +1013,7 @@ class Pages
// Move manually ordered items into the beginning of the list. Order of the unlisted items does not change.
if (is_array($manual) && !empty($manual)) {
$new_list = array();
$new_list = [];
$i = count($manual);
foreach ($list as $key => $dummy) {
@@ -933,7 +1022,7 @@ class Pages
if ($order === false) {
$order = $i++;
}
$new_list[$key] = (int) $order;
$new_list[$key] = (int)$order;
}
$list = $new_list;
@@ -948,13 +1037,19 @@ class Pages
}
}
// Shuffles and associative array
/**
* Shuffles an associative array
*
* @param array $list
*
* @return array
*/
protected function arrayShuffle($list)
{
$keys = array_keys($list);
shuffle($keys);
$new = array();
$new = [];
foreach ($keys as $key) {
$new[$key] = $list[$key];
}

View File

@@ -11,7 +11,7 @@ use RocketTheme\Toolbox\File\YamlFile;
/**
* The Plugin object just holds the id and path to a plugin.
*
* @author RocketTheme
* @author RocketTheme
* @license MIT
*/
class Plugin implements EventSubscriberInterface
@@ -41,7 +41,7 @@ class Plugin implements EventSubscriberInterface
{
$methods = get_class_methods(get_called_class());
$list = array();
$list = [];
foreach ($methods as $method) {
if (strpos($method, 'on') === 0) {
$list[$method] = [$method, 0];
@@ -54,9 +54,9 @@ class Plugin implements EventSubscriberInterface
/**
* Constructor.
*
* @param string $name
* @param Grav $grav
* @param Config $config
* @param string $name
* @param Grav $grav
* @param Config $config
*/
public function __construct($name, Grav $grav, Config $config)
{
@@ -70,6 +70,7 @@ class Plugin implements EventSubscriberInterface
if (isset($this->grav['admin'])) {
return true;
}
return false;
}
@@ -83,12 +84,12 @@ class Plugin implements EventSubscriberInterface
foreach ($events as $eventName => $params) {
if (is_string($params)) {
$dispatcher->addListener($eventName, array($this, $params));
$dispatcher->addListener($eventName, [$this, $params]);
} elseif (is_string($params[0])) {
$dispatcher->addListener($eventName, array($this, $params[0]), isset($params[1]) ? $params[1] : 0);
$dispatcher->addListener($eventName, [$this, $params[0]], isset($params[1]) ? $params[1] : 0);
} else {
foreach ($params as $listener) {
$dispatcher->addListener($eventName, array($this, $listener[0]), isset($listener[1]) ? $listener[1] : 0);
$dispatcher->addListener($eventName, [$this, $listener[0]], isset($listener[1]) ? $listener[1] : 0);
}
}
}
@@ -104,12 +105,12 @@ class Plugin implements EventSubscriberInterface
foreach ($events as $eventName => $params) {
if (is_string($params)) {
$dispatcher->removeListener($eventName, array($this, $params));
$dispatcher->removeListener($eventName, [$this, $params]);
} elseif (is_string($params[0])) {
$dispatcher->removeListener($eventName, array($this, $params[0]));
$dispatcher->removeListener($eventName, [$this, $params[0]]);
} else {
foreach ($params as $listener) {
$dispatcher->removeListener($eventName, array($this, $listener[0]));
$dispatcher->removeListener($eventName, [$this, $listener[0]]);
}
}
}
@@ -122,15 +123,16 @@ class Plugin implements EventSubscriberInterface
*
* format: [plugin:myplugin_name](function_data)
*
* @param $content The string to perform operations upon
* @param $function The anonymous callback function
* @param string $internal_regex Optional internal regex to extra data from
* @param string $content The string to perform operations upon
* @param callable $function The anonymous callback function
* @param string $internal_regex Optional internal regex to extra data from
*
* @return string
*/
protected function parseLinks($content, $function, $internal_regex = '(.*)')
{
$regex = '/\[plugin:(?:'.$this->name.')\]\('.$internal_regex.'\)/i';
$regex = '/\[plugin:(?:' . $this->name . ')\]\(' . $internal_regex . '\)/i';
return preg_replace_callback($regex, $function, $content);
}
@@ -149,7 +151,7 @@ class Plugin implements EventSubscriberInterface
{
$class_name = $this->name;
$class_name_merged = $class_name . '.merged';
$defaults = $this->config->get('plugins.'. $class_name, []);
$defaults = $this->config->get('plugins.' . $class_name, []);
$page_header = $page->header();
$header = [];
if (!isset($page_header->$class_name_merged) && isset($page_header->$class_name)) {
@@ -180,6 +182,7 @@ class Plugin implements EventSubscriberInterface
} else {
$header = array_merge($header, $params);
}
// Return configurations as a new data config class
return new Data($header);
}
@@ -187,11 +190,12 @@ class Plugin implements EventSubscriberInterface
/**
* Persists to disk the plugin parameters currently stored in the Grav Config object
*
* @param string $plugin_name The name of the plugin whose config it should store.
* @param string $plugin_name The name of the plugin whose config it should store.
*
* @return true
*/
public static function saveConfig($plugin_name) {
public static function saveConfig($plugin_name)
{
if (!$plugin_name) {
return false;
}

View File

@@ -12,7 +12,7 @@ use RocketTheme\Toolbox\Event\EventSubscriberInterface;
* The Plugins object holds an array of all the plugin objects that
* Grav knows about
*
* @author RocketTheme
* @author RocketTheme
* @license MIT
*/
class Plugins extends Iterator
@@ -29,7 +29,7 @@ class Plugins extends Iterator
{
/** @var Config $config */
$config = self::getGrav()['config'];
$plugins = (array) $config->get('plugins');
$plugins = (array)$config->get('plugins');
$inflector = self::getGrav()['inflector'];
@@ -52,8 +52,8 @@ class Plugins extends Iterator
require_once $filePath;
$pluginClassFormat = [
'Grav\\Plugin\\'.ucfirst($plugin).'Plugin',
'Grav\\Plugin\\'.$inflector->camelize($plugin).'Plugin'
'Grav\\Plugin\\' . ucfirst($plugin) . 'Plugin',
'Grav\\Plugin\\' . $inflector->camelize($plugin) . 'Plugin'
];
$pluginClassName = false;
@@ -65,7 +65,8 @@ class Plugins extends Iterator
}
if (false === $pluginClassName) {
throw new \RuntimeException(sprintf("Plugin '%s' class not found! Try reinstalling this plugin.", $plugin));
throw new \RuntimeException(sprintf("Plugin '%s' class not found! Try reinstalling this plugin.",
$plugin));
}
$instance = new $pluginClassName($plugin, self::getGrav(), $config);
@@ -77,6 +78,11 @@ class Plugins extends Iterator
return $this->items;
}
/**
* Add a plugin
*
* @param $plugin
*/
public function add($plugin)
{
if (is_object($plugin)) {
@@ -91,10 +97,10 @@ class Plugins extends Iterator
*/
public static function all()
{
$list = array();
$list = [];
$locator = Grav::instance()['locator'];
$plugins = (array) $locator->findResources('plugins://', false);
$plugins = (array)$locator->findResources('plugins://', false);
foreach ($plugins as $path) {
$iterator = new \DirectoryIterator($path);
@@ -117,6 +123,13 @@ class Plugins extends Iterator
return $list;
}
/**
* Get a plugin by name
*
* @param string $name
*
* @return Data|null
*/
public static function get($name)
{
$blueprints = new Blueprints('plugins://');

View File

@@ -22,7 +22,7 @@ class ConfigServiceProvider implements ServiceProviderInterface
public function register(Container $container)
{
$container['setup'] = function ($c) {
return static::setup($c)->init();
return static::setup($c);
};
$container['blueprints'] = function ($c) {

View File

@@ -9,11 +9,19 @@ class Session extends \RocketTheme\Toolbox\Session\Session
protected $grav;
protected $session;
/**
* Session constructor.
*
* @param Grav $grav
*/
public function __construct(Grav $grav)
{
$this->grav = $grav;
}
/**
* Session init
*/
public function init()
{
/** @var Uri $uri */
@@ -37,10 +45,7 @@ class Session extends \RocketTheme\Toolbox\Session\Session
if ($config->get('system.session.enabled') || $is_admin) {
// Define session service.
parent::__construct(
$session_timeout,
$session_path
);
parent::__construct($session_timeout, $session_path);
$domain = $uri->host();
if ($domain == 'localhost') {

View File

@@ -22,7 +22,7 @@ use Grav\Common\Page\Page;
* [tag][grav][path/to/item2]
* [tag][dog][path/to/item3]
*
* @author RocketTheme
* @author RocketTheme
* @license MIT
*/
class Taxonomy
@@ -32,10 +32,12 @@ class Taxonomy
/**
* Constructor that resets the map
*
* @param Grav $grav
*/
public function __construct(Grav $grav)
{
$this->taxonomy_map = array();
$this->taxonomy_map = [];
$this->grav = $grav;
}
@@ -43,7 +45,7 @@ class Taxonomy
* Takes an individual page and processes the taxonomies configured in its header. It
* then adds those taxonomies to the map
*
* @param Page $page the page to process
* @param Page $page the page to process
* @param array $page_taxonomy
*/
public function addTaxonomy(Page $page, $page_taxonomy = null)
@@ -59,10 +61,10 @@ class Taxonomy
/** @var Config $config */
$config = $this->grav['config'];
if ($config->get('site.taxonomies')) {
foreach ((array) $config->get('site.taxonomies') as $taxonomy) {
foreach ((array)$config->get('site.taxonomies') as $taxonomy) {
if (isset($page_taxonomy[$taxonomy])) {
foreach ((array) $page_taxonomy[$taxonomy] as $item) {
$this->taxonomy_map[$taxonomy][(string) $item][$page->path()] = array('slug' => $page->slug());
foreach ((array)$page_taxonomy[$taxonomy] as $item) {
$this->taxonomy_map[$taxonomy][(string)$item][$page->path()] = ['slug' => $page->slug()];
}
}
}
@@ -73,8 +75,9 @@ class Taxonomy
* Returns a new Page object with the sub-pages containing all the values set for a
* particular taxonomy.
*
* @param array $taxonomies taxonomies to search, eg ['tag'=>['animal','cat']]
* @param string $operator can be 'or' or 'and' (defaults to 'or')
* @param array $taxonomies taxonomies to search, eg ['tag'=>['animal','cat']]
* @param string $operator can be 'or' or 'and' (defaults to 'or')
*
* @return Collection Collection object set to contain matches found in the taxonomy map
*/
public function findTaxonomy($taxonomies, $operator = 'and')
@@ -83,7 +86,7 @@ class Taxonomy
$results = [];
foreach ((array)$taxonomies as $taxonomy => $items) {
foreach ((array) $items as $item) {
foreach ((array)$items as $item) {
if (isset($this->taxonomy_map[$taxonomy][$item])) {
$matches[] = $this->taxonomy_map[$taxonomy][$item];
}
@@ -108,6 +111,7 @@ class Taxonomy
* Gets and Sets the taxonomy map
*
* @param array $var the taxonomy map
*
* @return array the taxonomy map
*/
public function taxonomy($var = null)
@@ -115,6 +119,7 @@ class Taxonomy
if ($var) {
$this->taxonomy_map = $var;
}
return $this->taxonomy_map;
}
}

View File

@@ -2,7 +2,12 @@
namespace Grav\Common;
use Grav\Common\Config\Config;
use RocketTheme\Toolbox\File\YamlFile;
/**
* Class Theme
* @package Grav\Common
*/
class Theme extends Plugin
{
public $name;
@@ -10,7 +15,7 @@ class Theme extends Plugin
/**
* Constructor.
*
* @param Grav $grav
* @param Grav $grav
* @param Config $config
* @param string $name
*/
@@ -24,11 +29,12 @@ class Theme extends Plugin
/**
* Persists to disk the theme parameters currently stored in the Grav Config object
*
* @param string $theme_name The name of the theme whose config it should store.
* @param string $theme_name The name of the theme whose config it should store.
*
* @return true
*/
public static function saveConfig($theme_name) {
public static function saveConfig($theme_name)
{
if (!$theme_name) {
return false;
}

View File

@@ -12,7 +12,7 @@ use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* The Themes object holds an array of all the theme objects that Grav knows about.
*
* @author RocketTheme
* @author RocketTheme
* @license MIT
*/
class Themes extends Iterator
@@ -23,6 +23,11 @@ class Themes extends Iterator
/** @var Config */
protected $config;
/**
* Themes constructor.
*
* @param Grav $grav
*/
public function __construct(Grav $grav)
{
parent::__construct();
@@ -51,7 +56,7 @@ class Themes extends Iterator
try {
$instance = $themes->load();
} catch (\InvalidArgumentException $e) {
throw new \RuntimeException($this->current(). ' theme could not be found');
throw new \RuntimeException($this->current() . ' theme could not be found');
}
if ($instance instanceof EventSubscriberInterface) {
@@ -73,10 +78,10 @@ class Themes extends Iterator
*/
public function all()
{
$list = array();
$list = [];
$locator = Grav::instance()['locator'];
$themes = (array) $locator->findResources('themes://', false);
$themes = (array)$locator->findResources('themes://', false);
foreach ($themes as $path) {
$iterator = new \DirectoryIterator($path);
@@ -102,7 +107,8 @@ class Themes extends Iterator
/**
* Get theme configuration or throw exception if it cannot be found.
*
* @param string $name
* @param string $name
*
* @return Data
* @throws \RuntimeException
*/
@@ -126,7 +132,9 @@ class Themes extends Iterator
// Find thumbnail.
$thumb = "themes://{$name}/thumbnail.jpg";
if ($path = $this->grav['locator']->findResource($thumb, false)) {
$path = $this->grav['locator']->findResource($thumb, false);
if ($path) {
$blueprint->set('thumbnail', $this->grav['base_url'] . '/' . $path);
}
@@ -149,7 +157,7 @@ class Themes extends Iterator
*/
public function current()
{
return (string) $this->config->get('system.pages.theme');
return (string)$this->config->get('system.pages.theme');
}
/**
@@ -176,10 +184,9 @@ class Themes extends Iterator
if (!is_object($class)) {
$themeClassFormat = [
'Grav\\Theme\\'.ucfirst($name),
'Grav\\Theme\\'.$inflector->camelize($name)
'Grav\\Theme\\' . ucfirst($name),
'Grav\\Theme\\' . $inflector->camelize($name)
];
$themeClassName = false;
foreach ($themeClassFormat as $themeClass) {
if (class_exists($themeClass)) {
@@ -253,8 +260,8 @@ class Themes extends Iterator
/**
* Load theme configuration.
*
* @param string $name Theme name
* @param Config $config Configuration class
* @param string $name Theme name
* @param Config $config Configuration class
*/
protected function loadConfiguration($name, Config $config)
{
@@ -265,7 +272,7 @@ class Themes extends Iterator
/**
* Load theme languages.
*
* @param Config $config Configuration class
* @param Config $config Configuration class
*/
protected function loadLanguages(Config $config)
{
@@ -282,7 +289,7 @@ class Themes extends Iterator
if ($languages) {
$languages = call_user_func_array('array_replace_recursive', $languages);
$config->getLanguages()->mergeRecursive($languages);
$this->grav['languages']->mergeRecursive($languages);
}
}
}
@@ -311,7 +318,7 @@ class Themes extends Iterator
// Load class
if (file_exists($file)) {
return include_once($file);
return include_once($file);
}
}

View File

@@ -3,6 +3,7 @@ namespace Grav\Common\Twig;
use Grav\Common\Grav;
use Grav\Common\Config\Config;
use Grav\Common\Language\Language;
use Grav\Common\Page\Page;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use RocketTheme\Toolbox\Event\Event;
@@ -12,7 +13,7 @@ use RocketTheme\Toolbox\Event\Event;
* that is optimized so that it only needs to be initialized once and can be reused for individual
* page template rendering as well as the main site template rendering.
*
* @author RocketTheme
* @author RocketTheme
* @license MIT
*/
class Twig
@@ -25,7 +26,7 @@ class Twig
/**
* @var array
*/
public $twig_vars;
public $twig_vars = [];
/**
* @var array
@@ -55,6 +56,8 @@ class Twig
/**
* Constructor
*
* @param Grav $grav
*/
public function __construct(Grav $grav)
{
@@ -73,7 +76,6 @@ class Twig
$config = $this->grav['config'];
/** @var UniformResourceLocator $locator */
$locator = $this->grav['locator'];
$debugger = $this->grav['debugger'];
/** @var Language $language */
$language = $this->grav['language'];
@@ -87,7 +89,7 @@ class Twig
// handle language templates if available
if ($language->enabled()) {
$lang_templates = $locator->findResource('theme://templates/'.($active_language ? $active_language : $language->getDefault()));
$lang_templates = $locator->findResource('theme://templates/' . ($active_language ? $active_language : $language->getDefault()));
if ($lang_templates) {
$this->twig_paths[] = $lang_templates;
}
@@ -98,8 +100,8 @@ class Twig
$this->grav->fireEvent('onTwigTemplatePaths');
$this->loader = new \Twig_Loader_Filesystem($this->twig_paths);
$this->loaderArray = new \Twig_Loader_Array(array());
$loader_chain = new \Twig_Loader_Chain(array($this->loaderArray, $this->loader));
$this->loaderArray = new \Twig_Loader_Array([]);
$loader_chain = new \Twig_Loader_Chain([$this->loaderArray, $this->loader]);
$params = $config->get('system.twig');
if (!empty($params['cache'])) {
@@ -114,7 +116,8 @@ class Twig
return new \Twig_Function_Function($name);
}
return new \Twig_Function_Function(function() {});
return new \Twig_Function_Function(function () {
});
});
}
@@ -124,7 +127,8 @@ class Twig
return new \Twig_Filter_Function($name);
}
return new \Twig_Filter_Function(function() {});
return new \Twig_Filter_Function(function () {
});
});
}
@@ -143,21 +147,21 @@ class Twig
$this->grav->fireEvent('onTwigExtensions');
// Set some standard variables for twig
$this->twig_vars = array(
'config' => $config,
'uri' => $this->grav['uri'],
'base_dir' => rtrim(ROOT_DIR, '/'),
'base_url' => $this->grav['base_url'] . $language_append,
'base_url_simple' => $this->grav['base_url'],
'base_url_absolute' => $this->grav['base_url_absolute'] . $language_append,
'base_url_relative' => $this->grav['base_url_relative'] . $language_append,
'theme_dir' => $locator->findResource('theme://'),
'theme_url' => $this->grav['base_url'] .'/'. $locator->findResource('theme://', false),
'site' => $config->get('site'),
'assets' => $this->grav['assets'],
'taxonomy' => $this->grav['taxonomy'],
'browser' => $this->grav['browser'],
);
$this->twig_vars = $this->twig_vars + [
'config' => $config,
'uri' => $this->grav['uri'],
'base_dir' => rtrim(ROOT_DIR, '/'),
'base_url' => $this->grav['base_url'] . $language_append,
'base_url_simple' => $this->grav['base_url'],
'base_url_absolute' => $this->grav['base_url_absolute'] . $language_append,
'base_url_relative' => $this->grav['base_url_relative'] . $language_append,
'theme_dir' => $locator->findResource('theme://'),
'theme_url' => $this->grav['base_url'] . '/' . $locator->findResource('theme://', false),
'site' => $config->get('site'),
'assets' => $this->grav['assets'],
'taxonomy' => $this->grav['taxonomy'],
'browser' => $this->grav['browser'],
];
}
}
@@ -195,6 +199,7 @@ class Twig
*
* @param Page $item The page item to render
* @param string $content Optional content override
*
* @return string The rendered output
* @throws \Twig_Error_Loader
*/
@@ -203,7 +208,7 @@ class Twig
$content = $content !== null ? $content : $item->content();
// override the twig header vars for local resolution
$this->grav->fireEvent('onTwigPageVariables', new Event(['page' => $item]));
$this->grav->fireEvent('onTwigPageVariables', new Event(['page' => $item]));
$twig_vars = $this->twig_vars;
$twig_vars['page'] = $item;
@@ -214,6 +219,8 @@ class Twig
$modular_twig = $item->modularTwig();
$process_twig = isset($item->header()->process['twig']) ? $item->header()->process['twig'] : false;
$output = '';
try {
// Process Modular Twig
if ($modular_twig) {
@@ -240,10 +247,11 @@ class Twig
* and optional array of variables
*
* @param string $template template to render with
* @param array $vars Optional variables
* @param array $vars Optional variables
*
* @return string
*/
public function processTemplate($template, $vars = array())
public function processTemplate($template, $vars = [])
{
// override the twig header vars for local resolution
$this->grav->fireEvent('onTwigTemplateVariables');
@@ -264,11 +272,12 @@ class Twig
* Process a Twig template directly by using a Twig string
* and optional array of variables
*
* @param string $string string to render.
* @param array $vars Optional variables
* @param string $string string to render.
* @param array $vars Optional variables
*
* @return string
*/
public function processString($string, array $vars = array())
public function processString($string, array $vars = [])
{
// override the twig header vars for local resolution
$this->grav->fireEvent('onTwigStringVariables');
@@ -291,6 +300,7 @@ class Twig
* page and handles all the layout for the site display.
*
* @param string $format Output format (defaults to HTML).
*
* @return string the rendered output
* @throws \RuntimeException
*/
@@ -301,7 +311,6 @@ class Twig
$pages = $this->grav['pages'];
$page = $this->grav['page'];
$content = $page->content();
$config = $this->grav['config'];
$twig_vars = $this->twig_vars;
@@ -326,9 +335,9 @@ class Twig
} catch (\Twig_Error_Loader $e) {
$error_msg = $e->getMessage();
// Try html version of this template if initial template was NOT html
if ($ext != '.html'.TWIG_EXT) {
if ($ext != '.html' . TWIG_EXT) {
try {
$output = $this->twig->render($page->template().'.html'.TWIG_EXT, $twig_vars);
$output = $this->twig->render($page->template() . '.html' . TWIG_EXT, $twig_vars);
} catch (\Twig_Error_Loader $e) {
throw new \RuntimeException($error_msg, 400, $e);
}
@@ -345,6 +354,7 @@ class Twig
* the one being passed in
*
* @param string $template the template name
*
* @return string the template name
*/
public function template($template)

View File

@@ -5,12 +5,13 @@ use Grav\Common\Grav;
use Grav\Common\Utils;
use Grav\Common\Markdown\Parsedown;
use Grav\Common\Markdown\ParsedownExtra;
use Grav\Common\Uri;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* The Twig extension adds some filters and functions that are useful for Grav
*
* @author RocketTheme
* @author RocketTheme
* @license MIT
*/
class TwigExtension extends \Twig_Extension
@@ -19,6 +20,9 @@ class TwigExtension extends \Twig_Extension
protected $debugger;
protected $config;
/**
* TwigExtension constructor.
*/
public function __construct()
{
$this->grav = Grav::instance();
@@ -43,9 +47,9 @@ class TwigExtension extends \Twig_Extension
*/
public function getGlobals()
{
return array(
return [
'grav' => $this->grav,
);
];
}
/**
@@ -56,30 +60,30 @@ class TwigExtension extends \Twig_Extension
public function getFilters()
{
return [
new \Twig_SimpleFilter('*ize', [$this,'inflectorFilter']),
new \Twig_SimpleFilter('*ize', [$this, 'inflectorFilter']),
new \Twig_SimpleFilter('absolute_url', [$this, 'absoluteUrlFilter']),
new \Twig_SimpleFilter('contains', [$this, 'containsFilter']),
new \Twig_SimpleFilter('defined', [$this, 'definedDefaultFilter']),
new \Twig_SimpleFilter('ends_with', [$this, 'endsWithFilter']),
new \Twig_SimpleFilter('fieldName', [$this,'fieldNameFilter']),
new \Twig_SimpleFilter('ksort', [$this,'ksortFilter']),
new \Twig_SimpleFilter('fieldName', [$this, 'fieldNameFilter']),
new \Twig_SimpleFilter('ksort', [$this, 'ksortFilter']),
new \Twig_SimpleFilter('ltrim', [$this, 'ltrimFilter']),
new \Twig_SimpleFilter('markdown', [$this, 'markdownFilter']),
new \Twig_SimpleFilter('md5', [$this,'md5Filter']),
new \Twig_SimpleFilter('md5', [$this, 'md5Filter']),
new \Twig_SimpleFilter('nicetime', [$this, 'nicetimeFilter']),
new \Twig_SimpleFilter('randomize', [$this,'randomizeFilter']),
new \Twig_SimpleFilter('modulus', [$this,'modulusFilter']),
new \Twig_SimpleFilter('randomize', [$this, 'randomizeFilter']),
new \Twig_SimpleFilter('modulus', [$this, 'modulusFilter']),
new \Twig_SimpleFilter('rtrim', [$this, 'rtrimFilter']),
new \Twig_SimpleFilter('pad', [$this, 'padFilter']),
new \Twig_SimpleFilter('safe_email', [$this,'safeEmailFilter']),
new \Twig_SimpleFilter('safe_truncate', ['\Grav\Common\Utils','safeTruncate']),
new \Twig_SimpleFilter('safe_truncate_html', ['\Grav\Common\Utils','safeTruncateHTML']),
new \Twig_SimpleFilter('sort_by_key', [$this,'sortByKeyFilter']),
new \Twig_SimpleFilter('safe_email', [$this, 'safeEmailFilter']),
new \Twig_SimpleFilter('safe_truncate', ['\Grav\Common\Utils', 'safeTruncate']),
new \Twig_SimpleFilter('safe_truncate_html', ['\Grav\Common\Utils', 'safeTruncateHTML']),
new \Twig_SimpleFilter('sort_by_key', [$this, 'sortByKeyFilter']),
new \Twig_SimpleFilter('starts_with', [$this, 'startsWithFilter']),
new \Twig_SimpleFilter('t', [$this, 'translate']),
new \Twig_SimpleFilter('ta', [$this, 'translateArray']),
new \Twig_SimpleFilter('truncate', ['\Grav\Common\Utils','truncate']),
new \Twig_SimpleFilter('truncate_html', ['\Grav\Common\Utils','truncateHTML']),
new \Twig_SimpleFilter('truncate', ['\Grav\Common\Utils', 'truncate']),
new \Twig_SimpleFilter('truncate_html', ['\Grav\Common\Utils', 'truncateHTML']),
];
}
@@ -112,7 +116,8 @@ class TwigExtension extends \Twig_Extension
/**
* Filters field name by changing dot notation into array notation.
*
* @param string $str
* @param string $str
*
* @return string
*/
public function fieldNameFilter($str)
@@ -125,7 +130,8 @@ class TwigExtension extends \Twig_Extension
/**
* Protects email address.
*
* @param string $str
* @param string $str
*
* @return string
*/
public function safeEmailFilter($str)
@@ -133,8 +139,9 @@ class TwigExtension extends \Twig_Extension
$email = '';
$str_len = strlen($str);
for ($i = 0; $i < $str_len; $i++) {
$email .= "&#" . ord($str[$i]). ";";
$email .= "&#" . ord($str[$i]) . ";";
}
return $email;
}
@@ -142,7 +149,8 @@ class TwigExtension extends \Twig_Extension
* Returns array in a random order.
*
* @param array $original
* @param int $offset Can be used to return only slice of the array.
* @param int $offset Can be used to return only slice of the array.
*
* @return array
*/
public function randomizeFilter($original, $offset = 0)
@@ -160,41 +168,44 @@ class TwigExtension extends \Twig_Extension
shuffle($random);
$sizeOf = sizeof($original);
for ($x=0; $x < $sizeOf; $x++) {
for ($x = 0; $x < $sizeOf; $x++) {
if ($x < $offset) {
$sorted[] = $original[$x];
} else {
$sorted[] = array_shift($random);
}
}
return $sorted;
}
/**
* Returns the modulus of an integer
*
* @param int $number
* @param int $divider
* @param int $number
* @param int $divider
* @param array $items array of items to select from to return
*
* @return int
*/
public function modulusFilter($number, $divider, $items = null)
{
if (is_string($number)) {
$number = strlen($number);
}
public function modulusFilter($number, $divider, $items = null)
{
if (is_string($number)) {
$number = strlen($number);
}
$remainder = $number % $divider;
$remainder = $number % $divider;
if (is_array($items)) {
if (isset($items[$remainder])) {
return $items[$remainder];
} else {
return $items[0];
}
}
return $remainder;
}
if (is_array($items)) {
if (isset($items[$remainder])) {
return $items[$remainder];
} else {
return $items[0];
}
}
return $remainder;
}
/**
* Inflector supports following notations:
@@ -211,21 +222,22 @@ class TwigExtension extends \Twig_Extension
*
* @param string $action
* @param string $data
* @param int $count
* @param int $count
*
* @return mixed
*/
public function inflectorFilter($action, $data, $count = null)
{
$action = $action.'ize';
$action = $action . 'ize';
$inflector = $this->grav['inflector'];
if (in_array(
$action,
['titleize','camelize','underscorize','hyphenize', 'humanize','ordinalize','monthize']
['titleize', 'camelize', 'underscorize', 'hyphenize', 'humanize', 'ordinalize', 'monthize']
)) {
return $inflector->$action($data);
} elseif (in_array($action, ['pluralize','singularize'])) {
} elseif (in_array($action, ['pluralize', 'singularize'])) {
if ($count) {
return $inflector->$action($data, $count);
} else {
@@ -240,6 +252,7 @@ class TwigExtension extends \Twig_Extension
* Return MD5 hash from the input.
*
* @param string $str
*
* @return string
*/
public function md5Filter($str)
@@ -277,11 +290,13 @@ class TwigExtension extends \Twig_Extension
* Return ksorted collection.
*
* @param array $array
*
* @return array
*/
public function ksortFilter(array $array)
{
ksort($array);
return $array;
}
@@ -314,14 +329,32 @@ class TwigExtension extends \Twig_Extension
}
if ($long_strings) {
$periods = array("NICETIME.SECOND", "NICETIME.MINUTE", "NICETIME.HOUR", "NICETIME.DAY", "NICETIME.WEEK", "NICETIME.MONTH", "NICETIME.YEAR", "NICETIME.DECADE");
$periods = [
"NICETIME.SECOND",
"NICETIME.MINUTE",
"NICETIME.HOUR",
"NICETIME.DAY",
"NICETIME.WEEK",
"NICETIME.MONTH",
"NICETIME.YEAR",
"NICETIME.DECADE"
];
} else {
$periods = array("NICETIME.SEC", "NICETIME.MIN", "NICETIME.HR", "NICETIME.DAY", "NICETIME.WK", "NICETIME.MO", "NICETIME.YR", "NICETIME.DEC");
$periods = [
"NICETIME.SEC",
"NICETIME.MIN",
"NICETIME.HR",
"NICETIME.DAY",
"NICETIME.WK",
"NICETIME.MO",
"NICETIME.YR",
"NICETIME.DEC"
];
}
$lengths = array("60","60","24","7","4.35","12","10");
$lengths = ["60", "60", "24", "7", "4.35", "12", "10"];
$now = time();
$now = time();
// check if unix timestamp
if ((string)(int)$date == $date) {
@@ -337,15 +370,15 @@ class TwigExtension extends \Twig_Extension
// is it future date or past date
if ($now > $unix_date) {
$difference = $now - $unix_date;
$tense = $this->grav['language']->translate('NICETIME.AGO', null, true);
$difference = $now - $unix_date;
$tense = $this->grav['language']->translate('NICETIME.AGO', null, true);
} else {
$difference = $unix_date - $now;
$tense = $this->grav['language']->translate('NICETIME.FROM_NOW', null, true);
$difference = $unix_date - $now;
$tense = $this->grav['language']->translate('NICETIME.FROM_NOW', null, true);
}
for ($j = 0; $difference >= $lengths[$j] && $j < count($lengths)-1; $j++) {
for ($j = 0; $difference >= $lengths[$j] && $j < count($lengths) - 1; $j++) {
$difference /= $lengths[$j];
}
@@ -355,7 +388,9 @@ class TwigExtension extends \Twig_Extension
$periods[$j] .= '_PLURAL';
}
if ($this->grav['language']->getTranslation($this->grav['language']->getLanguage(), $periods[$j] . '_MORE_THAN_TWO')) {
if ($this->grav['language']->getTranslation($this->grav['language']->getLanguage(),
$periods[$j] . '_MORE_THAN_TWO')
) {
if ($difference > 2) {
$periods[$j] .= '_MORE_THAN_TWO';
}
@@ -366,14 +401,25 @@ class TwigExtension extends \Twig_Extension
return "$difference $periods[$j] {$tense}";
}
/**
* @param $string
*
* @return mixed
*/
public function absoluteUrlFilter($string)
{
$url = $this->grav['uri']->base();
$string = preg_replace('/((?:href|src) *= *[\'"](?!(http|ftp)))/i', "$1$url", $string);
return $string;
}
/**
* @param $string
*
* @return mixed|string
*/
public function markdownFilter($string)
{
$page = $this->grav['page'];
@@ -391,16 +437,34 @@ class TwigExtension extends \Twig_Extension
return $string;
}
/**
* @param $haystack
* @param $needle
*
* @return bool
*/
public function startsWithFilter($haystack, $needle)
{
return Utils::startsWith($haystack, $needle);
}
/**
* @param $haystack
* @param $needle
*
* @return bool
*/
public function endsWithFilter($haystack, $needle)
{
return Utils::endsWith($haystack, $needle);
}
/**
* @param $value
* @param null $default
*
* @return null
*/
public function definedDefaultFilter($value, $default = null)
{
if (isset($value)) {
@@ -410,21 +474,43 @@ class TwigExtension extends \Twig_Extension
}
}
/**
* @param $value
* @param null $chars
*
* @return string
*/
public function rtrimFilter($value, $chars = null)
{
return rtrim($value, $chars);
}
/**
* @param $value
* @param null $chars
*
* @return string
*/
public function ltrimFilter($value, $chars = null)
{
return ltrim($value, $chars);
}
/**
* @return mixed
*/
public function translate()
{
return $this->grav['language']->translate(func_get_args());
}
/**
* @param $key
* @param $index
* @param null $lang
*
* @return mixed
*/
public function translateArray($key, $index, $lang = null)
{
return $this->grav['language']->translateArray($key, $index, $lang);
@@ -435,6 +521,7 @@ class TwigExtension extends \Twig_Extension
*
* @param string $input
* @param int $multiplier
*
* @return string
*/
public function repeatFunc($input, $multiplier)
@@ -447,24 +534,30 @@ class TwigExtension extends \Twig_Extension
*
* @example {{ url('theme://images/logo.png')|default('http://www.placehold.it/150x100/f4f4f4') }}
*
* @param string $input Resource to be located.
* @param bool $domain True to include domain name.
* @param string $input Resource to be located.
* @param bool $domain True to include domain name.
*
* @return string|null Returns url to the resource or null if resource was not found.
*/
public function urlFunc($input, $domain = false)
{
if (!trim((string) $input)) {
if (!trim((string)$input)) {
return false;
}
if (strpos((string) $input, '://')) {
if ($this->grav['config']->get('system.absolute_urls', false)) {
$domain = true;
}
if (strpos((string)$input, '://')) {
/** @var UniformResourceLocator $locator */
$locator = $this->grav['locator'];
// Get relative path to the resource (or false if not found).
$resource = $locator->findResource((string) $input, false);
$resource = $locator->findResource((string)$input, false);
} else {
$resource = (string) $input;
$resource = (string)$input;
}
/** @var Uri $uri */
@@ -478,7 +571,8 @@ class TwigExtension extends \Twig_Extension
*
* @example {{ evaluate('grav.language.getLanguage') }}
*
* @param string $input String to be evaluated
* @param string $input String to be evaluated
*
* @return string Returns the evaluated string
*/
public function evaluateFunc($input)
@@ -491,7 +585,7 @@ class TwigExtension extends \Twig_Extension
* (c) 2011 Fabien Potencier
*
* @param \Twig_Environment $env
* @param $context
* @param $context
*/
public function dump(\Twig_Environment $env, $context)
{
@@ -525,11 +619,12 @@ class TwigExtension extends \Twig_Extension
* Output a Gist
*
* @param string $id
*
* @return string
*/
public function gistFunc($id)
{
return '<script src="https://gist.github.com/'.$id.'.js"></script>';
return '<script src="https://gist.github.com/' . $id . '.js"></script>';
}
/**
@@ -556,7 +651,7 @@ class TwigExtension extends \Twig_Extension
*/
public static function padFilter($input, $pad_length, $pad_string = " ", $pad_type = STR_PAD_RIGHT)
{
return str_pad($input, (int) $pad_length, $pad_string, $pad_type);
return str_pad($input, (int)$pad_length, $pad_string, $pad_type);
}
@@ -569,7 +664,7 @@ class TwigExtension extends \Twig_Extension
*/
public function arrayFunc($value)
{
return (array) $value;
return (array)$value;
}
/**
@@ -625,18 +720,17 @@ class TwigExtension extends \Twig_Extension
/**
* Used to add a nonce to a form. Call {{ nonce_field('action') }} specifying a string representing the action.
*
* For maximum protection, ensure that the string representing the action is as specific as possible.
* For maximum protection, ensure that the string representing the action is as specific as possible
*
* @todo evaluate if adding referrer or not
*
* @param string action the action
* @param string nonceParamName a custom nonce param name
* @param string $action the action
* @param string $nonceParamName a custom nonce param name
*
* @return string the nonce input field
*/
public function nonceFieldFunc($action, $nonceParamName = 'nonce')
{
$string = '<input type="hidden" id="' . $nonceParamName . '" name="' . $nonceParamName . '" value="' . Utils::getNonce($action) .'" />';
$string = '<input type="hidden" id="' . $nonceParamName . '" name="' . $nonceParamName . '" value="' . Utils::getNonce($action) . '" />';
return $string;
}
}

View File

@@ -11,6 +11,7 @@ trait WriteCacheFileTrait
use GravTrait;
protected static $umask;
/**
* This exists so template cache files use the same
* group between apache and cli

View File

@@ -6,7 +6,7 @@ use Grav\Common\Page\Page;
/**
* The URI object provides information about the current URL
*
* @author RocketTheme
* @author RocketTheme
* @license MIT
*/
class Uri
@@ -15,68 +15,236 @@ class Uri
public $url;
protected $basename;
protected $base;
protected $root;
protected $basename;
protected $bits;
protected $content_path;
protected $extension;
protected $host;
protected $content_path;
protected $env;
protected $params;
protected $path;
protected $paths;
protected $scheme;
protected $port;
protected $query;
protected $params;
protected $root;
protected $root_path;
protected $uri;
/**
* Constructor.
* Constructor
*/
public function __construct()
{
$name = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost');
// Remove port from HTTP_HOST generated $name
$name = Utils::substrToString($name, ':');
// resets
$this->paths = [];
$this->params = [];
$this->query = [];
$this->name = $this->buildHostname();
$this->env = $this->buildEnvironment();
$this->port = $this->buildPort();
$this->uri = $this->buildUri();
$this->scheme = $this->buildScheme();
$this->base = $this->buildBaseUrl();
$this->host = $this->buildHost();
$this->root_path = $this->buildRootPath();
$this->root = $this->base . $this->root_path;
$this->url = $this->base . $this->uri;
}
/**
* Return the hostname from $_SERVER, validated and without port
*
* @return string
*/
private function buildHostname()
{
$hostname = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost');
// Remove port from HTTP_HOST generated $hostname
$hostname = Utils::substrToString($hostname, ':');
// Validate the hostname
$name = preg_match(Uri::HOSTNAME_REGEX, $name) ? $name : 'unknown';
$hostname = $this->validateHostname($hostname) ? $hostname : 'unknown';
$port = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80;
$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
return $hostname;
}
$root_path = str_replace(' ', '%20', rtrim(substr($_SERVER['PHP_SELF'], 0, strpos($_SERVER['PHP_SELF'], 'index.php')), '/'));
/**
* Validate a hostname
*
* @param string $hostname The hostname
*
* @return boolean
*/
public function validateHostname($hostname)
{
return (bool)preg_match(Uri::HOSTNAME_REGEX, $hostname);
}
/**
* Get the port from $_SERVER
*
* @return string
*/
private function buildPort()
{
$port = isset($_SERVER['SERVER_PORT']) ? (string)$_SERVER['SERVER_PORT'] : '80';
return $port;
}
/**
* Get the Uri from $_SERVER
*
* @return string
*/
private function buildUri()
{
$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
return $uri;
}
private function buildScheme()
{
// set the base
if (isset($_SERVER['HTTPS'])) {
$base = (strtolower(@$_SERVER['HTTPS']) == 'on') ? 'https://' : 'http://';
$scheme = (strtolower(@$_SERVER['HTTPS']) == 'on') ? 'https://' : 'http://';
} else {
$base = 'http://';
$scheme = 'http://';
}
// add the sever name
$base .= $name;
return $scheme;
}
// add the port of needed
if ($port != '80' && $port != '443') {
$base .= ":".$port;
}
/**
* Get the base URI with port if needed
*
* @return string
*/
private function buildBaseUrl()
{
return $this->scheme . $this->name;
}
/**
* Get the Grav Root Path
*
* @return string
*/
private function buildRootPath()
{
$root_path = str_replace(' ', '%20', rtrim(substr($_SERVER['PHP_SELF'], 0, strpos($_SERVER['PHP_SELF'], 'index.php')), '/'));
// check if userdir in the path and workaround PHP bug with PHP_SELF
if (strpos($uri, '/~') !== false && strpos($_SERVER['PHP_SELF'], '/~') === false) {
$root_path = substr($uri, 0, strpos($uri, '/', 1)) . $root_path;
if (strpos($this->uri, '/~') !== false && strpos($_SERVER['PHP_SELF'], '/~') === false) {
$root_path = substr($this->uri, 0, strpos($this->uri, '/', 1)) . $root_path;
}
return $root_path;
}
/**
* Returns the hostname
*
* @return string
*/
private function buildHost()
{
return $this->name;
}
private function buildEnvironment()
{
// set hostname
$address = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '::1';
// check for localhost variations
if ($name == 'localhost' || $address == '::1' || $address == '127.0.0.1') {
$this->host = 'localhost';
if ($this->name == 'localhost' || $address == '::1' || $address == '127.0.0.1') {
$env = 'localhost';
} else {
$this->host = $name;
$env = $this->name;
}
$this->base = $base;
$this->root = $base . $root_path;
$this->url = $base . $uri;
return $env;
}
/**
* Initialize the URI class with a url passed via parameter.
* Used for testing purposes.
*
* @param string $url the URL to use in the class
*
* @return string
*/
public function initializeWithUrl($url = '')
{
if (!$url) {
return $this;
}
$this->paths = [];
$this->params = [];
$this->query = [];
$this->name = [];
$this->env = [];
$this->port = [];
$this->uri = [];
$this->base = [];
$this->host = [];
$this->root = [];
$this->url = [];
$grav = Grav::instance();
$language = $grav['language'];
$uri_bits = Uri::parseUrl($url);
$this->name = $uri_bits['host'];
$this->port = isset($uri_bits['port']) ? $uri_bits['port'] : '80';
$this->uri = $uri_bits['path'];
// set active language
$uri = $language->setActiveFromUri($this->uri);
if (isset($uri_bits['params'])) {
$this->params = $uri_bits['params'];
}
if (isset($uri_bits['query'])) {
$this->uri .= '?' . $uri_bits['query'];
parse_str($uri_bits['query'], $this->query);
}
$this->base = $this->buildBaseUrl();
$this->host = $this->buildHost();
$this->env = $this->buildEnvironment();
$this->root_path = $this->buildRootPath();
$this->root = $this->base . $this->root_path;
$this->url = $this->root . $uri;
$this->path = $uri;
return $this;
}
/**
* Initialize the URI class by providing url and root_path arguments
*
* @param string $url
* @param string $root_path
*
* @return $this
*/
public function initializeWithUrlAndRootPath($url, $root_path)
{
$this->initializeWithUrl($url);
$this->root_path = $root_path;
return $this;
}
/**
@@ -89,10 +257,14 @@ class Uri
$config = $grav['config'];
$language = $grav['language'];
// resets
$this->paths = [];
$this->params = [];
$this->query = [];
// add the port to the base for non-standard ports
if ($config->get('system.reverse_proxy_setup') === false && $this->port != '80' && $this->port != '443') {
$this->base .= ":" . $this->port;
}
// Set some defaults
$this->root = $this->base . $this->root_path;
$this->url = $this->base . $this->uri;
// get any params and remove them
$uri = str_replace($this->root, '', $this->url);
@@ -122,7 +294,9 @@ class Uri
// process query string
if (isset($bits['query']) && isset($bits['path'])) {
$this->query = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
if (!$this->query) {
$this->query = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
}
$uri = $bits['path'];
}
@@ -140,8 +314,8 @@ class Uri
$valid_page_types = implode('|', $config->get('system.pages.types'));
// Strip the file extension for valid page types
if (preg_match("/\.(".$valid_page_types.")$/", $parts['basename'])) {
$uri = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, $parts['dirname']), DS). '/' .$parts['filename'];
if (preg_match("/\.(" . $valid_page_types . ")$/", $parts['basename'])) {
$uri = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, $parts['dirname']), DS) . '/' . $parts['filename'];
}
// set the new url
@@ -151,6 +325,11 @@ class Uri
if ($this->content_path != '') {
$this->paths = explode('/', $this->content_path);
}
// Set some Grav stuff
$grav['base_url_absolute'] = $this->rootUrl(true);
$grav['base_url_relative'] = $this->rootUrl(false);
$grav['base_url'] = $grav['config']->get('system.absolute_urls') ? $grav['base_url_absolute'] : $grav['base_url_relative'];
}
/**
@@ -165,7 +344,7 @@ class Uri
{
if (strpos($uri, $delimiter) !== false) {
$bits = explode('/', $uri);
$path = array();
$path = [];
foreach ($bits as $bit) {
if (strpos($bit, $delimiter) !== false) {
$param = explode($delimiter, $bit);
@@ -179,13 +358,15 @@ class Uri
}
$uri = '/' . ltrim(implode('/', $path), '/');
}
return $uri;
}
/**
* Return URI path.
*
* @param string $id
* @param string $id
*
* @return string
*/
public function paths($id = null)
@@ -200,8 +381,9 @@ class Uri
/**
* Return route to the current URI. By default route doesn't include base path.
*
* @param bool $absolute True to include full path.
* @param bool $domain True to include domain. Works only if first parameter is also true.
* @param bool $absolute True to include full path.
* @param bool $domain True to include domain. Works only if first parameter is also true.
*
* @return string
*/
public function route($absolute = false, $domain = false)
@@ -212,8 +394,10 @@ class Uri
/**
* Return full query string or a single query attribute.
*
* @param string $id Optional attribute.
* @return string
* @param string $id Optional attribute. Get a single query attribute if set
* @param bool $raw If true and $id is not set, return the full query array. Otherwise return the query string
*
* @return string|array Returns an array if $id = null and $raw = true
*/
public function query($id = null, $raw = false)
{
@@ -223,6 +407,10 @@ class Uri
if ($raw) {
return $this->query;
} else {
if (!$this->query) {
return '';
}
return http_build_query($this->query);
}
}
@@ -231,8 +419,9 @@ class Uri
/**
* Return all or a single query parameter as a URI compatible string.
*
* @param string $id Optional parameter name.
* @param string $id Optional parameter name.
* @param boolean $array return the array format or not
*
* @return null|string
*/
public function params($id = null, $array = false)
@@ -244,16 +433,16 @@ class Uri
if ($array) {
return $this->params;
}
$output = array();
$output = [];
foreach ($this->params as $key => $value) {
$output[] = $key . $config->get('system.param_sep') . $value;
$params = '/'.implode('/', $output);
$params = '/' . implode('/', $output);
}
} elseif (isset($this->params[$id])) {
if ($array) {
return $this->params[$id];
}
$params = "/{$id}". $config->get('system.param_sep') . $this->params[$id];
$params = "/{$id}" . $config->get('system.param_sep') . $this->params[$id];
}
return $params;
@@ -262,7 +451,8 @@ class Uri
/**
* Get URI parameter.
*
* @param string $id
* @param string $id
*
* @return bool|string
*/
public function param($id)
@@ -277,7 +467,8 @@ class Uri
/**
* Return URL.
*
* @param bool $include_host Include hostname.
* @param bool $include_host Include hostname.
*
* @return string
*/
public function url($include_host = false)
@@ -286,6 +477,7 @@ class Uri
return $this->url;
} else {
$url = (str_replace($this->base, '', rtrim($this->url, '/')));
return $url ? $url : '/';
}
}
@@ -301,6 +493,7 @@ class Uri
if ($path === '') {
$path = '/';
}
return $path;
}
@@ -316,9 +509,21 @@ class Uri
if (!$this->extension) {
$this->extension = $default;
}
return $this->extension;
}
/**
* Return the scheme of the URI
*
* @return String The scheme of the URI
*/
public function scheme()
{
return $this->scheme;
}
/**
* Return the host of the URI
*
@@ -329,6 +534,16 @@ class Uri
return $this->host;
}
/**
* Return the port number
*
* @return int
*/
public function port()
{
return $this->port;
}
/**
* Gets the environment name
*
@@ -336,7 +551,7 @@ class Uri
*/
public function environment()
{
return $this->host();
return $this->env;
}
@@ -363,7 +578,8 @@ class Uri
/**
* Return root URL to the site.
*
* @param bool $include_host Include hostname.
* @param bool $include_host Include hostname.
*
* @return mixed
*/
public function rootUrl($include_host = false)
@@ -372,6 +588,7 @@ class Uri
return $this->root;
} else {
$root = str_replace($this->base, '', $this->root);
return $root;
}
}
@@ -395,6 +612,7 @@ class Uri
*
* @param string $default
* @param string $attributes
*
* @return string
*/
public function referrer($default = null, $attributes = null)
@@ -450,7 +668,8 @@ class Uri
/**
* Is this an external URL? if it starts with `http` then yes, else false
*
* @param string $url the URL in question
* @param string $url the URL in question
*
* @return boolean is eternal state
*/
public function isExternal($url)
@@ -466,6 +685,7 @@ class Uri
* The opposite of built-in PHP method parse_url()
*
* @param $parsed_url
*
* @return string
*/
public static function buildUrl($parsed_url)
@@ -477,26 +697,241 @@ class Uri
$pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
$pass = ($user || $pass) ? "$pass@" : '';
$path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
$params = isset($parsed_url['params']) ? static::buildParams($parsed_url['params']) : '';
$query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
$fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
return "$scheme$user$pass$host$port$path$query$fragment";
return "$scheme$user$pass$host$port$path$params$query$fragment";
}
/**
* Converts links from absolute '/' or relative (../..) to a grav friendly format
*
* @param Page|the $page the current page to use as reference
* @param string $markdown_url the URL as it was written in the markdown
* @param string $type the type of URL, image | link
* @param null $relative if null, will use system default, if true will use relative links internally
*
* @return string the more friendly formatted url
*/
public static function convertUrl(Page $page, $markdown_url, $type = 'link', $relative = null)
public static function buildParams($params)
{
$grav = Grav::instance();
$params_string = '';
foreach ($params as $key => $value) {
$output[] = $key . $grav['config']->get('system.param_sep') . $value;
$params_string .= '/' . implode('/', $output);
}
return $params_string;
}
/**
* Converts links from absolute '/' or relative (../..) to a Grav friendly format
*
* @param Page $page the current page to use as reference
* @param string $url the URL as it was written in the markdown
* @param string $type the type of URL, image | link
* @param null $absolute if null, will use system default, if true will use absolute links internally
*
* @return string the more friendly formatted url
*/
public static function convertUrl(Page $page, $url, $type = 'link', $absolute = false)
{
$grav = Grav::instance();
$uri = $grav['uri'];
// Link processing should prepend language
$language = $grav['language'];
$language_append = '';
if ($type == 'link' && $language->enabled()) {
$language_append = $language->getLanguageURLPrefix();
}
// Handle Excerpt style $url array
if (is_array($url)) {
$url_path = $url['path'];
} else {
$url_path = $url;
}
$external = false;
$base = $grav['base_url_relative'];
$base_url = rtrim($base . $grav['pages']->base(), '/') . $language_append;
$pages_dir = $grav['locator']->findResource('page://');
// if absolute and starts with a base_url move on
if (isset($url['scheme']) && Utils::startsWith($url['scheme'], 'http')) {
$external = true;
} elseif (($base_url != '' && Utils::startsWith($url_path, $base_url)) ||
$url_path == '/' ||
Utils::startsWith($url_path, '#')) {
$url_path = $base_url . $url_path;
} else {
// see if page is relative to this or absolute
if (Utils::startsWith($url_path, '/')) {
$normalized_url = Utils::normalizePath($base_url . $url_path);
$normalized_path = Utils::normalizePath($pages_dir . $url_path);
} else {
$page_route = ($page->home() && !empty($url_path)) ? $page->rawRoute() : $page->route();
$normalized_url = $base_url . Utils::normalizePath($page_route . '/' . $url_path);
$normalized_path = Utils::normalizePath($page->path() . '/' . $url_path);
}
// special check to see if path checking is required.
$just_path = str_replace($normalized_url, '', $normalized_path);
if ($just_path == $page->path() || $normalized_url == '/') {
$url_path = $normalized_url;
} else {
$url_bits = static::parseUrl($normalized_path);
$full_path = ($url_bits['path']);
$raw_full_path = rawurldecode($full_path);
if (file_exists($raw_full_path)) {
$full_path = $raw_full_path;
} elseif (file_exists($full_path)) {
// do nothing
} else {
$full_path = false;
}
if ($full_path) {
$path_info = pathinfo($full_path);
$page_path = $path_info['dirname'];
$filename = '';
if ($url_path == '..') {
$page_path = $full_path;
} else {
// save the filename if a file is part of the path
if (is_file($full_path)) {
if ($path_info['extension'] != 'md') {
$filename = '/' . $path_info['basename'];
}
} else {
$page_path = $full_path;
}
}
// get page instances and try to find one that fits
$instances = $grav['pages']->instances();
if (isset($instances[$page_path])) {
/** @var Page $target */
$target = $instances[$page_path];
$url_bits['path'] = $base_url . rtrim($target->route(), '/') . $filename;
$url_path = Uri::buildUrl($url_bits);
} else {
$url_path = $normalized_url;
}
} else {
$url_path = $normalized_url;
}
}
}
// handle absolute URLs
if (!$external && ($absolute === true || $grav['config']->get('system.absolute_urls', false))) {
$url['scheme'] = str_replace('://', '', $uri->scheme());
$url['host'] = $uri->host();
if ($uri->port() != 80 && $uri->port() != 443) {
$url['port'] = $uri->port();
}
// check if page exists for this route, and if so, check if it has SSL enabled
$pages = $grav['pages'];
$routes = $pages->routes();
// if this is an image, get the proper path
$url_bits = pathinfo($url_path);
if (isset($url_bits['extension'])) {
$target_path = $url_bits['dirname'];
} else {
$target_path = $url_path;
}
// strip base from this path
$target_path = str_replace($uri->rootUrl(), '', $target_path);
// set to / if root
if (empty($target_path)) {
$target_path = '/';
}
// look to see if this page exists and has ssl enabled
if (isset($routes[$target_path])) {
$target_page = $pages->get($routes[$target_path]);
if ($target_page) {
$ssl_enabled = $target_page->ssl();
if (isset($ssl_enabled)) {
if ($ssl_enabled) {
$url['scheme'] = 'https';
} else {
$url['scheme'] = 'http';
}
}
}
}
}
// transform back to string/array as needed
if (is_array($url)) {
$url['path'] = $url_path;
} else {
$url = $url_path;
}
return $url;
}
public static function parseUrl($url)
{
$bits = parse_url($url);
$grav = Grav::instance();
list($stripped_path, $params) = static::extractParams($bits['path'], $grav['config']->get('system.param_sep'));
if (!empty($params)) {
$bits['path'] = $stripped_path;
$bits['params'] = $params;
}
return $bits;
}
public static function extractParams($uri, $delimiter)
{
$params = [];
if (strpos($uri, $delimiter) !== false) {
$bits = explode('/', $uri);
$path = [];
foreach ($bits as $bit) {
if (strpos($bit, $delimiter) !== false) {
$param = explode($delimiter, $bit);
if (count($param) == 2) {
$plain_var = filter_var(rawurldecode($param[1]), FILTER_SANITIZE_STRING);
$params[$param[0]] = $plain_var;
}
} else {
$path[] = $bit;
}
}
$uri = '/' . ltrim(implode('/', $path), '/');
}
return [$uri, $params];
}
/**
* Converts links from absolute '/' or relative (../..) to a Grav friendly format
*
* @param Page $page the current page to use as reference
* @param string $markdown_url the URL as it was written in the markdown
* @param string $type the type of URL, image | link
* @param null $relative if null, will use system default, if true will use relative links internally
*
* @return string the more friendly formatted url
*/
public static function convertUrlOld(Page $page, $markdown_url, $type = 'link', $relative = null)
{
$grav = Grav::instance();
/** @var Grav\Common\Language\Language $language */
$language = $grav['language'];
// Link processing should prepend language
@@ -509,7 +944,7 @@ class Uri
if (is_null($relative)) {
$base = $grav['base_url'];
} else {
$base = $relative ? $grav['base_url_relative'] : $grav['base_url_absolute'];
$base = $relative ? $grav['base_url_relative'] : $grav['base_url_absolute'];
}
$base_url = rtrim($base . $grav['pages']->base(), '/') . $language_append;
@@ -555,7 +990,6 @@ class Uri
$page_path = $path_info['dirname'];
$filename = '';
if ($markdown_url == '..') {
$page_path = $full_path;
} else {
@@ -572,8 +1006,10 @@ class Uri
// get page instances and try to find one that fits
$instances = $grav['pages']->instances();
if (isset($instances[$page_path])) {
/** @var Page $target */
$target = $instances[$page_path];
$url_bits['path'] = $base_url . rtrim($target->route(), '/') . $filename;
return Uri::buildUrl($url_bits);
}
@@ -584,8 +1020,8 @@ class Uri
/**
* Adds the nonce to a URL for a specific action
*
* @param string $url the url
* @param string $action the action
* @param string $url the url
* @param string $action the action
* @param string $nonceParamName the param name to use
*
* @return string the url with the nonce
@@ -593,7 +1029,7 @@ class Uri
public static function addNonce($url, $action, $nonceParamName = 'nonce')
{
$urlWithNonce = $url . '/' . $nonceParamName . Grav::instance()['config']->get('system.param_sep', ':') . Utils::getNonce($action);
return $urlWithNonce;
}
}

View File

@@ -4,7 +4,7 @@ namespace Grav\Common\User;
/**
* User authentication
*
* @author RocketTheme
* @author RocketTheme
* @license MIT
*/
abstract class Authentication
@@ -12,7 +12,8 @@ abstract class Authentication
/**
* Create password hash from plaintext password.
*
* @param string $password Plaintext password.
* @param string $password Plaintext password.
*
* @throws \RuntimeException
* @return string|bool
*/
@@ -34,8 +35,9 @@ abstract class Authentication
/**
* Verifies that a password matches a hash.
*
* @param string $password Plaintext password.
* @param string $hash Hash to verify against.
* @param string $password Plaintext password.
* @param string $hash Hash to verify against.
*
* @return int Returns 0 if the check fails, 1 if password matches, 2 if hash needs to be updated.
*/
public static function verify($password, $hash)

View File

@@ -10,10 +10,7 @@ use Grav\Common\Utils;
/**
* Group object
*
* @property mixed authenticated
* @property mixed password
* @property bool|string hashed_password
* @author RocketTheme
* @author RocketTheme
* @license MIT
*/
class Group extends Data
@@ -28,15 +25,18 @@ class Group extends Data
private static function groups()
{
$groups = self::getGrav()['config']->get('groups');
return $groups;
}
/**
* Checks if a group exists
*
* @param string $groupname
*
* @return object
*/
public static function group_exists($groupname)
public static function groupExists($groupname)
{
return isset(self::groups()[$groupname]);
}
@@ -44,11 +44,13 @@ class Group extends Data
/**
* Get a group by name
*
* @param string $groupname
*
* @return object
*/
public static function load($groupname)
{
if (self::group_exists($groupname)) {
if (self::groupExists($groupname)) {
$content = self::groups()[$groupname];
} else {
$content = [];
@@ -76,7 +78,7 @@ class Group extends Data
self::getGrav()['config']->set("groups.$this->groupname", []);
foreach($fields as $field) {
foreach ($fields as $field) {
if ($field['type'] == 'text') {
$value = $field['name'];
if (isset($this->items[$value])) {
@@ -87,8 +89,10 @@ class Group extends Data
$value = $field['name'];
$arrayValues = Utils::resolve($this->items, $field['name']);
if ($arrayValues) foreach($arrayValues as $arrayIndex => $arrayValue) {
self::getGrav()['config']->set("groups.$this->groupname.$value.$arrayIndex", $arrayValue);
if ($arrayValues) {
foreach ($arrayValues as $arrayIndex => $arrayValue) {
self::getGrav()['config']->set("groups.$this->groupname.$value.$arrayIndex", $arrayValue);
}
}
}
}
@@ -104,7 +108,8 @@ class Group extends Data
/**
* Remove a group
*
* @param string $username
* @param string $groupname
*
* @return bool True if the action was performed
*/
public static function remove($groupname)

View File

@@ -10,10 +10,10 @@ use Grav\Common\Utils;
/**
* User object
*
* @property mixed authenticated
* @property mixed password
* @property mixed authenticated
* @property mixed password
* @property bool|string hashed_password
* @author RocketTheme
* @author RocketTheme
* @license MIT
*/
class User extends Data
@@ -26,6 +26,7 @@ class User extends Data
* Always creates user object. To check if user exists, use $this->exists().
*
* @param string $username
*
* @return User
*/
public static function load($username)
@@ -56,6 +57,7 @@ class User extends Data
* Remove user account.
*
* @param string $username
*
* @return bool True if the action was performed
*/
public static function remove($username)
@@ -73,7 +75,8 @@ class User extends Data
*
* If user password needs to be updated, new information will be saved.
*
* @param string $password Plaintext password.
* @param string $password Plaintext password.
*
* @return bool
*/
public function authenticate($password)
@@ -88,8 +91,9 @@ class User extends Data
// the result
Authentication::verify(
$password,
self::getGrav()['config']->get('system.security.default_hash', '$2y$10$kwsyMVwM8/7j0K/6LHT.g.Fs49xOCTp2b8hh/S5.dPJuJcJB6T.UK')
self::getGrav()['config']->get('system.security.default_hash')
);
return false;
} else {
// Plain-text does match, we can update the hash and proceed
@@ -113,7 +117,7 @@ class User extends Data
$this->save();
}
return (bool) $result;
return (bool)$result;
}
/**
@@ -139,7 +143,8 @@ class User extends Data
/**
* Checks user authorization to the action.
*
* @param string $action
* @param string $action
*
* @return bool
*/
public function authorize($action)
@@ -156,21 +161,22 @@ class User extends Data
//Check group access level
$groups = $this->get('groups');
if ($groups) foreach($groups as $group) {
$permission = self::getGrav()['config']->get("groups.{$group}.access.{$action}");
if (Utils::isPositive($permission)) {
$return = true;
if ($groups) {
foreach ((array)$groups as $group) {
$permission = self::getGrav()['config']->get("groups.{$group}.access.{$action}");
$return = Utils::isPositive($permission);
if ($return === true) {
break;
}
}
}
//Check user access level
if (!$this->get('access')) {
return false;
}
if (Utils::resolve($this->get('access'), $action) !== null) {
$permission = $this->get("access.{$action}");
$return = Utils::isPositive($permission);
if ($this->get('access')) {
if (Utils::resolve($this->get('access'), $action) !== null) {
$permission = $this->get("access.{$action}");
$return = Utils::isPositive($permission);
}
}
return $return;
@@ -181,6 +187,7 @@ class User extends Data
* Ensures backwards compatibility
*
* @param string $action
*
* @deprecated use authorize()
* @return bool
*/

View File

@@ -18,6 +18,8 @@ abstract class Utils
protected static $nonces = [];
/**
* Check if the $haystack string starts with the substring $needle
*
* @param string $haystack
* @param string $needle
*
@@ -41,6 +43,8 @@ abstract class Utils
}
/**
* Check if the $haystack string ends with the substring $needle
*
* @param string $haystack
* @param string $needle
*
@@ -64,6 +68,8 @@ abstract class Utils
}
/**
* Check if the $haystack string contains the substring $needle
*
* @param string $haystack
* @param string $needle
*
@@ -79,13 +85,15 @@ abstract class Utils
*
* @param $haystack
* @param $needle
*
* @return string
*/
public static function substrToString($haystack, $needle)
{
if (static::contains($haystack, $needle)) {
return substr($haystack, 0, strpos($haystack,$needle));
return substr($haystack, 0, strpos($haystack, $needle));
}
return $haystack;
}
@@ -103,6 +111,8 @@ abstract class Utils
}
/**
* Return the Grav date formats allowed
*
* @return array
*/
public static function dateFormats()
@@ -120,6 +130,7 @@ abstract class Utils
if ($default_format) {
$date_formats = array_merge([$default_format => $default_format.' (e.g. '.$now->format($default_format).')'], $date_formats);
}
return $date_formats;
}
@@ -127,10 +138,11 @@ abstract class Utils
* Truncate text by number of characters but can cut off words.
*
* @param string $string
* @param int $limit Max number of characters.
* @param bool $up_to_break truncate up to breakpoint after char count
* @param string $break Break point.
* @param string $pad Appended padding to the end of the string.
* @param int $limit Max number of characters.
* @param bool $up_to_break truncate up to breakpoint after char count
* @param string $break Break point.
* @param string $pad Appended padding to the end of the string.
*
* @return string
*/
public static function truncate($string, $limit = 150, $up_to_break = false, $break = " ", $pad = "&hellip;")
@@ -155,8 +167,9 @@ abstract class Utils
/**
* Truncate text by number of characters in a "word-safe" manor.
*
* @param $string
* @param int $limit
* @param string $string
* @param int $limit
*
* @return string
*/
public static function safeTruncate($string, $limit = 150)
@@ -175,7 +188,7 @@ abstract class Utils
*/
public static function truncateHtml($text, $length = 100)
{
return Truncator::truncate($text, $length, array('length_in_chars' => true));
return Truncator::truncate($text, $length, ['length_in_chars' => true]);
}
/**
@@ -188,7 +201,7 @@ abstract class Utils
*/
public static function safeTruncateHtml($text, $length = 100)
{
return Truncator::truncate($text, $length, array('length_in_chars' => true, 'word_safe' => true));
return Truncator::truncate($text, $length, ['length_in_chars' => true, 'word_safe' => true]);
}
/**
@@ -206,8 +219,8 @@ abstract class Utils
/**
* Provides the ability to download a file to the browser
*
* @param $file the full path to the file to be downloaded
* @param bool $force_download as opposed to letting browser choose if to download or render
* @param string $file the full path to the file to be downloaded
* @param bool $force_download as opposed to letting browser choose if to download or render
*/
public static function download($file, $force_download = true)
{
@@ -223,7 +236,8 @@ abstract class Utils
if (!Utils::isFunctionDisabled('set_time_limit') && !ini_get('safe_mode') && function_exists('set_time_limit')) {
set_time_limit(0);
}
} catch (\Exception $e) {}
} catch (\Exception $e) {
}
ignore_user_abort(false);
@@ -264,7 +278,7 @@ abstract class Utils
/**
* Return the mimetype based on filename
*
* @param $extension Extension of file (eg .txt)
* @param string $extension Extension of file (eg "txt")
*
* @return string
*/
@@ -283,7 +297,7 @@ abstract class Utils
/**
* Normalize path by processing relative `.` and `..` syntax and merging path
*
* @param $path
* @param string $path
*
* @return string
*/
@@ -292,7 +306,7 @@ abstract class Utils
$root = ($path[0] === '/') ? '/' : '';
$segments = explode('/', trim($path, '/'));
$ret = array();
$ret = [];
foreach ($segments as $segment) {
if (($segment == '.') || empty($segment)) {
continue;
@@ -308,7 +322,9 @@ abstract class Utils
}
/**
* @param $function
* Check whether a function is disabled in the PHP settings
*
* @param string $function the name of the function to check
*
* @return bool
*/
@@ -318,6 +334,8 @@ abstract class Utils
}
/**
* Get the formatted timezones list
*
* @return array
*/
public static function timezones()
@@ -333,7 +351,7 @@ abstract class Utils
asort($offsets);
$timezone_list = array();
$timezone_list = [];
foreach ($offsets as $timezone => $offset) {
$offset_prefix = $offset < 0 ? '-' : '+';
$offset_formatted = gmdate('H:i', abs($offset));
@@ -344,41 +362,46 @@ abstract class Utils
}
return $timezone_list;
}
/**
* @param array $source
* @param $fn
* Recursively filter an array, filtering values by processing them through the $fn function argument
*
* @param array $source the Array to filter
* @param callable $fn the function to pass through each array item
*
* @return array
*/
public static function arrayFilterRecursive(Array $source, $fn)
{
$result = array();
foreach ($source as $key => $value)
{
if (is_array($value))
{
$result = [];
foreach ($source as $key => $value) {
if (is_array($value)) {
$result[$key] = static::arrayFilterRecursive($value, $fn);
continue;
}
if ($fn($key, $value))
{
if ($fn($key, $value)) {
$result[$key] = $value; // KEEP
continue;
}
}
return $result;
}
/**
* @param $string
* Checks if the passed path contains the language code prefix
*
* @param string $string The path
*
* @return bool
*/
public static function pathPrefixedByLangCode($string)
{
if (strlen($string) <= 3) {
return false;
}
$languages_enabled = self::getGrav()['config']->get('system.languages.supported', []);
if ($string[0] == '/' && $string[3] == '/' && in_array(substr($string, 1, 2), $languages_enabled)) {
@@ -389,9 +412,12 @@ abstract class Utils
}
/**
* @param $date
* Get the timestamp of a date
*
* @return int
* @param string $date a String expressed in the system.pages.dateformat.default format, with fallback to a
* strtotime argument
*
* @return int the timestamp
*/
public static function date2timestamp($date)
{
@@ -414,7 +440,13 @@ abstract class Utils
}
/**
* Get value of an array using dot notation
* Get value of an array element using dot notation
*
* @param array $array the Array to check
* @param string $path the dot notation path to check
* @param mixed $default a value to be returned if $path is not found in $array
*
* @return mixed the value found
*/
public static function resolve(array $array, $path, $default = null)
{
@@ -450,7 +482,7 @@ abstract class Utils
* with reverse proxy setups.
*
* @param string $action
* @param bool $plusOneTick if true, generates the token for the next tick (the next 12 hours)
* @param bool $plusOneTick if true, generates the token for the next tick (the next 12 hours)
*
* @return string the nonce string
*/
@@ -469,11 +501,10 @@ abstract class Utils
$i++;
}
return ( $i . '|' . $action . '|' . $username . '|' . $token . '|' . self::getGrav()['config']->get('security.salt'));
return ($i . '|' . $action . '|' . $username . '|' . $token . '|' . self::getGrav()['config']->get('security.salt'));
}
//Added in version 1.0.8 to ensure that existing nonces are not broken.
//TODO: to be removed
private static function generateNonceStringOldStyle($action, $plusOneTick = false)
{
if (isset(self::getGrav()['user'])) {
@@ -490,13 +521,14 @@ abstract class Utils
if ($plusOneTick) {
$i++;
}
return ( $i . '|' . $action . '|' . $username . '|' . $token . '|' . self::getGrav()['config']->get('security.salt'));
return ($i . '|' . $action . '|' . $username . '|' . $token . '|' . self::getGrav()['config']->get('security.salt'));
}
/**
* Get the time-dependent variable for nonce creation.
*
* @todo now a tick lasts a day. Once the day is passed, the nonce is not valid any more. Find a better way
* Now a tick lasts a day. Once the day is passed, the nonce is not valid any more. Find a better way
* to ensure nonces issued near the end of the day do not expire in that small amount of time
*
* @return int the time part of the nonce. Changes once every 24 hours
@@ -504,15 +536,16 @@ abstract class Utils
private static function nonceTick()
{
$secondsInHalfADay = 60 * 60 * 12;
return (int)ceil(time() / ( $secondsInHalfADay ));
return (int)ceil(time() / ($secondsInHalfADay));
}
/**
* Creates a hashed nonce tied to the passed action. Tied to the current user and time. The nonce for a given
* action is the same for 12 hours.
*
* @param string $action the action the nonce is tied to (e.g. save-user-admin or move-page-homepage)
* @param bool $plusOneTick if true, generates the token for the next tick (the next 12 hours)
* @param string $action the action the nonce is tied to (e.g. save-user-admin or move-page-homepage)
* @param bool $plusOneTick if true, generates the token for the next tick (the next 12 hours)
*
* @return string the nonce
*/
@@ -529,7 +562,6 @@ abstract class Utils
}
//Added in version 1.0.8 to ensure that existing nonces are not broken.
//TODO: to be removed
public static function getNonceOldStyle($action, $plusOneTick = false)
{
// Don't regenerate this again if not needed
@@ -545,7 +577,7 @@ abstract class Utils
/**
* Verify the passed nonce for the give action
*
* @param string $nonce the nonce to verify
* @param string $nonce the nonce to verify
* @param string $action the action to verify the nonce to
*
* @return boolean verified or not
@@ -570,7 +602,6 @@ abstract class Utils
//Added in version 1.0.8 to ensure that existing nonces are not broken.
//TODO: to be removed
//Nonce generated 0-12 hours ago
if ($nonce == self::getNonceOldStyle($action)) {
return true;
@@ -581,7 +612,6 @@ abstract class Utils
if ($nonce == self::getNonceOldStyle($action, $plusOneTick)) {
return true;
}
//End TODO: to be removed
//Invalid nonce
return false;

View File

@@ -24,6 +24,8 @@ class CleanCommand extends Command
* @var array
*/
protected $paths_to_remove = [
'codeception.yml',
'tests/',
'user/plugins/email/vendor/swiftmailer/swiftmailer/.travis.yml',
'user/plugins/email/vendor/swiftmailer/swiftmailer/build.xml',
'user/plugins/email/vendor/swiftmailer/swiftmailer/composer.json',

View File

@@ -55,6 +55,7 @@ class SandboxCommand extends ConsoleCommand
'/system' => '/system',
'/vendor' => '/vendor',
'/webserver-configs' => '/webserver-configs',
'/codeception.yml' => '/codeception.yml',
);
/**

View File

@@ -30,6 +30,9 @@ class ConsoleCommand extends Command
/**
*
*/
protected function serve() { }
protected function serve()
{
}
}
}

View File

@@ -5,6 +5,7 @@ use Grav\Common\GPM\GPM;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Question\ConfirmationQuestion;
/**
* Class InfoCommand
@@ -34,6 +35,12 @@ class InfoCommand extends ConsoleCommand
InputOption::VALUE_NONE,
'Force fetching the new data remotely'
)
->addOption(
'all-yes',
'y',
InputOption::VALUE_NONE,
'Assumes yes (or best approach) instead of prompting'
)
->addArgument(
'package',
InputArgument::REQUIRED,
@@ -107,9 +114,62 @@ class InfoCommand extends ConsoleCommand
}
}
$type = rtrim($foundPackage->package_type, 's');
$updatable = $this->gpm->{'is' . $type . 'Updatable'}($foundPackage->slug);
$installed = $this->gpm->{'is' . $type . 'Installed'}($foundPackage->slug);
// display current version if installed and different
if ($installed && $updatable) {
$local = $this->gpm->{'getInstalled'. $type}($foundPackage->slug);
$this->output->writeln('');
$this->output->writeln("Currently installed version: <magenta>" . $local->version . "</magenta>");
$this->output->writeln('');
}
// display changelog information
$questionHelper = $this->getHelper('question');
$skipPrompt = $this->input->getOption('all-yes');
if (!$skipPrompt) {
$question = new ConfirmationQuestion("Would you like to read the changelog? [y|N] ",
false);
$answer = $questionHelper->ask($this->input, $this->output, $question);
if ($answer) {
$changelog = $foundPackage->changelog;
$this->output->writeln("");
foreach ($changelog as $version => $log) {
$title = $version . ' [' . $log['date'] . ']';
$content = preg_replace_callback("/\d\.\s\[\]\(#(.*)\)/", function ($match) {
return "\n" . ucfirst($match[1]) . ":";
}, $log['content']);
$this->output->writeln('<cyan>'.$title.'</cyan>');
$this->output->writeln(str_repeat('-', strlen($title)));
$this->output->writeln($content);
$this->output->writeln("");
$question = new ConfirmationQuestion("Press [ENTER] to continue or [q] to quit ", true);
if (!$questionHelper->ask($this->input, $this->output, $question)) {
break;
}
$this->output->writeln("");
}
}
}
$this->output->writeln('');
$this->output->writeln("You can install this package by typing:");
$this->output->writeln(" <green>" . $this->argv . " install</green> <cyan>" . $foundPackage->slug . "</cyan>");
if ($installed && $updatable) {
$this->output->writeln("You can update this package by typing:");
$this->output->writeln(" <green>" . $this->argv . " update</green> <cyan>" . $foundPackage->slug . "</cyan>");
} else {
$this->output->writeln("You can install this package by typing:");
$this->output->writeln(" <green>" . $this->argv . " install</green> <cyan>" . $foundPackage->slug . "</cyan>");
}
$this->output->writeln('');
}

55
tests/_bootstrap.php Normal file
View File

@@ -0,0 +1,55 @@
<?php
// This is global bootstrap for autoloading
namespace Grav;
use Codeception\Util\Fixtures;
use Faker\Factory;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
ini_set('error_log', __DIR__ . '/error.log');
// Ensure vendor libraries exist
$autoload = __DIR__ . '/../vendor/autoload.php';
if (!is_file($autoload)) {
throw new \RuntimeException("Please run: <i>bin/grav install</i>");
}
use Grav\Common\Grav;
// Register the auto-loader.
$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
date_default_timezone_set(@date_default_timezone_get());
// Set internal encoding if mbstring loaded
if (!extension_loaded('mbstring')) {
throw new \RuntimeException("'mbstring' extension is not loaded. This is required for Grav to run correctly");
}
mb_internal_encoding('UTF-8');
// Get the Grav instance
$grav = Grav::instance(['loader' => $loader]);
$grav['uri']->init();
$grav['debugger']->init();
$grav['assets']->init();
$grav['config']->set('system.cache.enabled', false);
/** @var UniformResourceLocator $locator */
$locator = $grav['locator'];
$locator->addPath('tests', '', 'tests', false);
// Set default $_SERVER value used for nonces
empty( $_SERVER['HTTP_CLIENT_IP'] ) && $_SERVER['HTTP_CLIENT_IP'] = '127.0.0.1';
$fake = Factory::create();
Fixtures::add('grav', $grav);
Fixtures::add('fake', $fake);

View File

@@ -0,0 +1,26 @@
<?php
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* @SuppressWarnings(PHPMD)
*/
class AcceptanceTester extends \Codeception\Actor
{
use _generated\AcceptanceTesterActions;
/**
* Define custom actions here
*/
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* @SuppressWarnings(PHPMD)
*/
class FunctionalTester extends \Codeception\Actor
{
use _generated\FunctionalTesterActions;
/**
* Define custom actions here
*/
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Helper;
// here you can define custom actions
// all public methods declared in helper class will be available in $I
class Acceptance extends \Codeception\Module
{
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Helper;
// here you can define custom actions
// all public methods declared in helper class will be available in $I
class Functional extends \Codeception\Module
{
}

View File

@@ -0,0 +1,80 @@
<?php
namespace Helper;
use Codeception;
// here you can define custom actions
// all public methods declared in helper class will be available in $I
/**
* Class Unit
* @package Helper
*/
class Unit extends Codeception\Module
{
/**
* HOOK: used after configuration is loaded
*/
public function _initialize() {
}
/**
* HOOK: on every Actor class initialization
*/
public function _cleanup() {
}
/**
* HOOK: before suite
*
* @param array $settings
*/
public function _beforeSuite($settings = []) {
}
/**
* HOOK: after suite
**/
public function _afterSuite() {
}
/**
* HOOK: before each step
*
* @param Codeception\Step $step*
*/
public function _beforeStep(Codeception\Step $step) {
}
/**
* HOOK: after each step
*
* @param Codeception\Step $step
*/
public function _afterStep(Codeception\Step $step) {
}
/**
* HOOK: before each suite
*
* @param Codeception\TestCase $test
*/
public function _before(Codeception\TestCase $test) {
}
/**
* HOOK: before each suite
*
* @param Codeception\TestCase $test
*/
public function _after(Codeception\TestCase $test) {
}
/**
* HOOK: on fail
*
* @param Codeception\TestCase $test
* @param $fail
*/
public function _failed(Codeception\TestCase $test, $fail) {
}
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* @SuppressWarnings(PHPMD)
*/
class UnitTester extends \Codeception\Actor
{
use _generated\UnitTesterActions;
/**
* Define custom actions here
*/
}

View File

@@ -0,0 +1,12 @@
# Codeception Test Suite Configuration
#
# Suite for acceptance tests.
# Perform tests in browser using the WebDriver or PhpBrowser.
# If you need both WebDriver and PHPBrowser tests - create a separate suite.
class_name: AcceptanceTester
modules:
enabled:
- PhpBrowser:
url: http://localhost:8080/grav
- \Helper\Acceptance

View File

@@ -0,0 +1,2 @@
<?php
// Here you can initialize variables that will be available to your tests

View File

@@ -0,0 +1,10 @@
---
title: Item 1-1-1
---
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

View File

@@ -0,0 +1,10 @@
---
title: Item 1-1-2
---
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

View File

@@ -0,0 +1,10 @@
---
title: Item 1-1-3
---
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

View File

@@ -0,0 +1,10 @@
---
title: Item 1-1
---
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

View File

@@ -0,0 +1,10 @@
---
title: Item 1-2-1
---
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

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