Merge branch 'master' into feature/PicoTwigExtension

Conflicts:
	CHANGELOG.md
This commit is contained in:
Daniel Rudolf 2015-11-29 22:19:57 +01:00
commit be46e19677
20 changed files with 800 additions and 498 deletions

26
.gitignore vendored
View file

@ -10,23 +10,27 @@ desktop.ini
.DS_Store
._*
# Travis
/build/phpdoc-*/
/build/phpdoc-*.git/
# Composer
composer.lock
composer.phar
vendor/*
/composer.lock
/composer.phar
/vendor
# User config
config/config.php
/config/config.php
# User themes
themes/*
!themes/default/*
/themes/*
!/themes/default
# User plugins
plugins/*
!plugins/0?-*
!plugins/1?-*
!plugins/DummyPlugin.php
/plugins/*
!/plugins/0?-*
!/plugins/1?-*
!/plugins/DummyPlugin.php
# User content
content/*
/content

View file

@ -8,12 +8,29 @@ php:
- hhvm
- nightly
matrix:
allow_failures:
- php: nightly
fast-finish: true
install:
- composer install
before_script:
- export PATH="$TRAVIS_BUILD_DIR/build:$TRAVIS_BUILD_DIR/vendor/bin:$PATH"
script:
- find . -type f -name '*.php' -print0 | xargs -0 -I file php -l file > /dev/null
- phpcs --standard=phpcs.xml "$TRAVIS_BUILD_DIR"
after_success:
- deploy-phpdoc-branch.sh
before_deploy:
- composer install
- tar -czf "pico-release-$TRAVIS_TAG.tar.gz" .htaccess README.md CHANGELOG.md CONTRIBUTING.md composer.json composer.lock LICENSE config content-sample lib plugins themes vendor index.php
- deploy-phpdoc-release.sh
- composer install --no-dev --optimize-autoloader
- find vendor/ -type d -path 'vendor/*/*/.git' -print0 | xargs -0 rm -rf
- mv index.php.dist index.php
- tar -czf "pico-release-$TRAVIS_TAG.tar.gz" README.md LICENSE CONTRIBUTING.md CHANGELOG.md composer.json composer.lock config content-sample lib plugins themes vendor .htaccess index.php
deploy:
provider: releases
@ -21,9 +38,7 @@ deploy:
file: pico-release-$TRAVIS_TAG.tar.gz
skip_cleanup: true
on:
repo: picocms/Pico
tags: true
php: 5.3
sudo: false

View file

@ -12,10 +12,24 @@ Released: -
want to parse the contents of a page, use the `content` filter instead
* [New] New `sort_by` filter to sort a array by a specified key or key path
* [New] New `map` filter to get the values of the given key or key path
* [New] New PHP version check in `index.php`
* [Changed] Improve documentation
* [Changed] Improve table styling in default theme
* [Changed] Update composer version constraints; almost all dependencies will
have pending updates, run `composer update`
* [Changed] Throw a RuntimeException when the `content` dir isn't accessible
* [Changed] Reuse `ParsedownExtra` object; new `onParsedownRegistration` event
* [Changed] `$config['rewrite_url']` is now always available
* [Changed] `DummyPlugin` class is now final
* [Changed] Various small improvements and changes...
* [Fixed] `PicoDeprecated`: Sanitize `content_dir` and `base_url` options when
reading `config.php` in Picos root dir
* [Fixed] Replace `urldecode()` (deprecated RFC 1738) with `rawurldecode()`
(RFC 3986) in `Page::evaluateRequestUrl()`
* [Fixed] #272: Encode URLs using `rawurlencode()` in `Pico::getPageUrl()`
* [Fixed] #274: Prevent double slashes in `base_url`
* [Fixed] #285: Make `index.php` work when installed as a composer dependency
* [Fixed] #291: Force `Pico::$requestUrl` to have no leading/trailing slash
```
### Version 1.0.0-beta.1

View file

@ -12,7 +12,9 @@ Issues
If you want to report an *issue* with Pico's core, please create a new [Issue](https://github.com/picocms/Pico/issues) on GitHub. Concerning problems with plugins or themes, please refer to the website of the developer of this plugin or theme.
Before creating a [new Issue on GitHub](https://github.com/picocms/Pico/issues/new), please make sure the problem wasn't reported yet using [GitHubs search engine](https://github.com/picocms/Pico/search?type=Issues). Please describe your issue as clear as possible and always include steps to reproduce the problem.
Before creating a [new Issue on GitHub](https://github.com/picocms/Pico/issues/new), please make sure the problem wasn't reported yet using [GitHubs search engine](https://github.com/picocms/Pico/search?type=Issues).
Please describe your issue as clear as possible and always include the *Pico version* you're using. Provided that you're using *plugins*, include a list of them too. We need information about the *actual and expected behavior*, the *steps to reproduce* the problem, and what steps have you taken to resolve the problem by yourself (i.e. *your own troubleshooting*)?
Contributing code
-----------------
@ -45,7 +47,7 @@ With this command you can specify a file or folder to limit which files it will
### Keep documentation in sync
Pico accepts the problems of having redundant documentation on different places (concretely Pico's inline user docs, the `README.md` and the website) for the sake of a better user experience. When updating the docs, please make sure the keep them in sync.
Pico accepts the problems of having redundant documentation on different places (concretely Pico's inline user docs, the `README.md` and the website) for the sake of a better user experience. When updating the docs, please make sure to keep them in sync.
If you update the [`README.md`](https://github.com/picocms/Pico/blob/master/README.md) or [`content-sample/index.md`](https://github.com/picocms/Pico/blob/master/content-sample/index.md), please make sure to update the corresponding files in the [`_docs`](https://github.com/picocms/Pico/tree/gh-pages/_docs/) folder of the `gh-pages` branch (i.e. [Pico's website](http://picocms.org/docs.html)) and vice versa. Unfortunately this involves three (!) different markdown parsers. If you're experiencing problems, use Pico's [`erusev/parsedown-extra`](https://github.com/erusev/parsedown-extra) as a reference. You can try to make the contents compatible to [Redcarpet](https://github.com/vmg/redcarpet) by yourself, otherwise please address the issues in your pull request message and we'll take care of it.
@ -78,44 +80,18 @@ As soon as development reaches a point where feedback is appreciated, a pull req
Build & Release process
-----------------------
This is work in progress. Please refer to [#268](https://github.com/picocms/Pico/issues/268) for details.
We're using [Travis CI](https://travis-ci.com) to automate the build & release process of Pico. It generates and deploys [phpDoc](http://phpdoc.org) class docs for new releases and on every commit to the `master` branch. Travis also prepares new releases by generating Pico's pre-built packages and uploading them to GitHub. Please refer to [our `.travis.yml`](https://github.com/picocms/Pico/blob/master/.travis.yml) for details.
<!--
As insinuated above, it is important that each commit to `master` is deployable. Once development of a new Pico release is finished, trigger Pico's build & release process by pushing a new Git tag. This tag should reference a (usually empty) commit on `master`, which message should adhere to the following template:
Defined below is a specification to which the Build and Release process of Pico should follow. We use `travis-ci` to automate the process, and each commit to `master` should be releasable.
```
Version 1.0.0
#### Commit phase
- Commit changes
- Create & Push Git tag
- Trigger automatic build process...
Example commit message:
Pico 1.0.1
* [Security] ...
* [New] ...
* [Changed] ...
* [Fixed] ...
* [Removed] ...
```
*Please submit pull-requests with a properly
formatted commit message/SemVer increase to avoid the need for manual amendments.*
#### Analysis phase
- Run through `scrutinizer-ci`?
#### Packaging phase
- Run composer locally
- Create a ZIP archive (so vendor/ is included)
- Build documentation, output goes to a new folder in the `gh-pages` branch
#### Release phase
- Create new Git release at tag
- Upload ZIP archive
- Upload documentation to the `gh-pages` branch
- Set Symlink for latest documentation (http://picocms.org/docs/latest)
- Update release information on GitHub with:
- Release title (taken from changelog)
- Changelog
#### Announcements
- Where to announce new Pico release?
-->
Travis CI will draft the new [release on GitHub](https://github.com/picocms/Pico/releases) automatically, but will require you to manually amend the descriptions formatting. The latest Pico version is always available at https://github.com/picocms/Pico/releases/latest, so please make sure to publish this URL rather than version-specific URLs. [Packagist](http://packagist.org/packages/picocms/pico) will be updated automatically.

View file

@ -46,11 +46,11 @@ Upgrading Pico is very easy: You just have to replace all of Pico's files - that
Pico follows [Semantic Versioning 2.0][SemVer] and uses version numbers like `MAJOR`.`MINOR`.`PATCH`. When we update...
- the `PATCH` version (e.g. `1.0.0` to `1.0.1`), we made backwards-compatible bug fixes. It's then sufficient to extract [Pico's latest release][LatestRelease] to your existing installation directory and overwriting all files.
- the `PATCH` version (e.g. `1.0.0` to `1.0.1`), we made backwards-compatible bug fixes. It's then sufficient to extract [Pico's latest release][LatestRelease] to your existing installation directory and overwriting all files. Alternatively you can either use the [*source code* of Pico's latest release][LatestRelease] or pull from Pico's Git repository, but are then required to update Pico's [composer][] dependencies manually by running `php composer.phar update`.
- the `MINOR` version (e.g. `1.0` to `1.1`), we added functionality in a backwards-compatible manner, but anyway recommend you to "install" Pico newly. Backup all of your files, empty your installation directory and install Pico as elucidated above. You can then copy your `config/config.php` and `content` directory without any change. If applicable, you can also copy the folder of your custom theme within the `themes` directory. Provided that you're using plugins, also copy all of your plugins from the `plugins` directory.
- the `MAJOR` version (e.g. `1.0` to `2.0`), a appropriate upgrade tutorial will be provided.
- the `MAJOR` version (e.g. `1.0` to `2.0`), we made incompatible API changes. We will then provide a appropriate upgrade tutorial.
Upgrading Pico 0.8 or 0.9 to Pico 1.0 is a special case. The new `PicoDeprecated` plugin ensures backwards compatibility, so you basically can follow the above upgrade instructions as if we updated the `MINOR` version. However, we recommend you to take some further steps to confine the necessity of `PicoDeprecated` as far as possible. For more information about what has changed with Pico 1.0 and a step-by-step upgrade tutorial, please refer to the [upgrade page of our website][HelpUpgrade].
@ -115,6 +115,6 @@ You want to contribute to Pico? We really appreciate that! You can help make Pic
[IssuesSearch]: https://github.com/picocms/Pico/search?type=Issues
[PullRequests]: https://github.com/picocms/Pico/pulls
[ContributionGuidelines]: https://github.com/picocms/Pico/blob/master/CONTRIBUTING.md
[EditInlineDocs]: https://github.com/picocms/Pico/blob/master/content-sample/index.md
[EditInlineDocs]: https://github.com/picocms/Pico/edit/master/content-sample/index.md
[EditUserDocs]: https://github.com/picocms/Pico/tree/gh-pages/_docs
[EditDevDocs]: https://github.com/picocms/Pico/tree/gh-pages/_plugin-dev

28
build/deploy-phpdoc-branch.sh Executable file
View file

@ -0,0 +1,28 @@
#!/usr/bin/env bash
if [ "$TRAVIS_PHP_VERSION" != "5.3" ]; then
echo "Skipping phpDoc deployment because this is not on the required runtime"
exit
fi
if [[ ",$DEPLOY_PHPDOC_BRANCHES," != *,"$TRAVIS_BRANCH",* ]]; then
echo "Skipping phpDoc deployment because this branch ($TRAVIS_BRANCH) is not permitted to deploy"
exit
fi
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
echo "Skipping phpDoc deployment because this pull request (#$TRAVIS_PULL_REQUEST) is not permitted to deploy"
exit
fi
PHPDOC_ID="${TRAVIS_BRANCH//\//_}"
generate-phpdoc.sh \
"$TRAVIS_BUILD_DIR" "$TRAVIS_BUILD_DIR/build/phpdoc-$PHPDOC_ID" \
"Pico 1.0 API Documentation ($TRAVIS_BRANCH branch)"
[ $? -eq 0 ] || exit 1
deploy-phpdoc.sh \
"$TRAVIS_REPO_SLUG" "heads/$TRAVIS_BRANCH @ $TRAVIS_COMMIT" "$TRAVIS_BUILD_DIR/build/phpdoc-$PHPDOC_ID" \
"$TRAVIS_REPO_SLUG" "gh-pages" "phpDoc/$PHPDOC_ID"
[ $? -eq 0 ] || exit 1

15
build/deploy-phpdoc-release.sh Executable file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env bash
[ "$DEPLOY_PHPDOC_RELEASES" == "true" ] || exit
PHPDOC_ID="${TRAVIS_BRANCH//\//_}"
generate-phpdoc.sh \
"$TRAVIS_BUILD_DIR" "$TRAVIS_BUILD_DIR/build/phpdoc-$PHPDOC_ID" \
"Pico 1.0 API Documentation ($TRAVIS_TAG)"
[ $? -eq 0 ] || exit 1
deploy-phpdoc.sh \
"$TRAVIS_REPO_SLUG" "tags/$TRAVIS_TAG" "$TRAVIS_BUILD_DIR/build/phpdoc-$PHPDOC_ID" \
"$TRAVIS_REPO_SLUG" "gh-pages" "phpDoc/$PHPDOC_ID"
[ $? -eq 0 ] || exit 1

109
build/deploy-phpdoc.sh Executable file
View file

@ -0,0 +1,109 @@
#!/usr/bin/env bash
set -e
# base variables
APP_NAME="$(basename "$0")"
BASE_PWD="$PWD"
# environment variables
# GITHUB_OAUTH_TOKEN GitHub authentication token, see https://github.com/settings/tokens
# parameters
SOURCE_REPO_SLUG="$1" # source GitHub repo (e.g. picocms/Pico)
SOURCE_REF="$2" # source reference (either "[ref] @ [commit]" or "[ref]",
# [ref] can be e.g. heads/master or tags/v1.0.0)
SOURCE_DIR="$3" # absolute source path
TARGET_REPO_SLUG="$4" # target GitHub repo (e.g. picocms/Pico)
TARGET_BRANCH="$5" # target branch (e.g. gh-pages)
TARGET_DIR="$6" # relative target path
# print parameters
echo "Deploying phpDocs..."
printf 'SOURCE_REPO_SLUG="%s"\n' "$SOURCE_REPO_SLUG"
printf 'SOURCE_REF="%s"\n' "$SOURCE_REF"
printf 'SOURCE_DIR="%s"\n' "$SOURCE_DIR"
printf 'TARGET_REPO_SLUG="%s"\n' "$TARGET_REPO_SLUG"
printf 'TARGET_BRANCH="%s"\n' "$TARGET_BRANCH"
printf 'TARGET_DIR="%s"\n' "$TARGET_DIR"
echo
# evaluate source reference
if [[ "$SOURCE_REF" == *" @ "* ]]; then
SOURCE_REF_TYPE="commit"
SOURCE_REF_HEAD="${SOURCE_REF% @ *}"
SOURCE_REF_COMMIT="${SOURCE_REF##* @ }"
if ! git check-ref-format "$SOURCE_REF_HEAD" || ! git rev-parse --verify "$SOURCE_REF_COMMIT" > /dev/null; then
echo "FATAL: $APP_NAME source reference '$SOURCE_REF' is invalid" >&2
exit 1
fi
elif git check-ref-format "$SOURCE_REF"; then
SOURCE_REF_TYPE="ref"
else
echo "FATAL: $APP_NAME source reference '$SOURCE_REF' is invalid" >&2
exit 1
fi
# clone repo
printf 'Cloning repo...\n'
GIT_DIR="$SOURCE_DIR.git"
git clone --branch="$TARGET_BRANCH" "https://github.com/$TARGET_REPO_SLUG.git" "$GIT_DIR"
# setup git
cd "$GIT_DIR"
git config user.name "Travis CI"
git config user.email "travis-ci@picocms.org"
if [ -n "$GITHUB_OAUTH_TOKEN" ]; then
git config credential.helper 'store --file=.git/credentials'
(umask 077 && echo "https://GitHub:$GITHUB_OAUTH_TOKEN@github.com" > .git/credentials)
fi
# copy phpdoc
printf '\nCopying phpDocs...\n'
[ ! -d "$TARGET_DIR" ] || rm -rf "$TARGET_DIR"
[ "${SOURCE_DIR:0:1}" == "/" ] || SOURCE_DIR="$BASE_PWD/$SOURCE_DIR"
cp -R "$SOURCE_DIR" "$TARGET_DIR"
# commit changes
printf '\nCommiting changes...\n'
git add --all "$TARGET_DIR"
git commit --message="Update phpDocumentor class docs for $SOURCE_REF"
# very simple race condition protection for concurrent Travis builds
# this is no definite protection (race conditions are still possible during `git push`),
# but it should give a basic protection without disabling concurrent builds completely
if [ "$SOURCE_REF_TYPE" == "commit" ]; then
# load branch data via GitHub APIv3
printf '\nRetrieving latest commit...\n'
LATEST_COMMIT_URL="https://api.github.com/repos/$SOURCE_REPO_SLUG/git/refs/$SOURCE_REF_HEAD"
if [ -n "$GITHUB_OAUTH_TOKEN" ]; then
LATEST_COMMIT_RESPONSE="$(wget -O- --header="Authorization: token $GITHUB_OAUTH_TOKEN" "$LATEST_COMMIT_URL" 2> /dev/null)"
else
LATEST_COMMIT_RESPONSE="$(wget -O- "$LATEST_COMMIT_URL" 2> /dev/null)"
fi
# evaluate JSON response
LATEST_COMMIT="$(echo "$LATEST_COMMIT_RESPONSE" | php -r "
\$json = json_decode(stream_get_contents(STDIN), true);
if (\$json !== null) {
if (isset(\$json['ref']) && (\$json['ref'] === 'refs/$SOURCE_REF_HEAD')) {
if (isset(\$json['object']) && isset(\$json['object']['sha'])) {
echo \$json['object']['sha'];
}
}
}
")"
# compare source reference against the latest commit
if [ "$LATEST_COMMIT" != "$SOURCE_REF_COMMIT" ]; then
echo "WARNING: $APP_NAME source reference '$SOURCE_REF' doesn't match the latest commit '$LATEST_COMMIT'" >&2
exit 0
fi
fi
# push changes
printf '\nPushing changes...\n'
git push "https://github.com/$TARGET_REPO_SLUG.git" "$TARGET_BRANCH:$TARGET_BRANCH"
echo

24
build/generate-phpdoc.sh Executable file
View file

@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -e
# parameters
PHPDOC_SOURCE_DIR="$1"
PHPDOC_TARGET_DIR="$2"
PHPDOC_TITLE="$3"
# print parameters
echo "Generating phpDocs..."
printf 'PHPDOC_SOURCE_DIR="%s"\n' "$PHPDOC_SOURCE_DIR"
printf 'PHPDOC_TARGET_DIR="%s"\n' "$PHPDOC_TARGET_DIR"
printf 'PHPDOC_TITLE="%s"\n' "$PHPDOC_TITLE"
echo
# generate phpdoc
phpdoc -d "$PHPDOC_SOURCE_DIR" \
-i "$PHPDOC_SOURCE_DIR/build/" \
-i "$PHPDOC_SOURCE_DIR/vendor/" \
-i "$PHPDOC_SOURCE_DIR/plugins/" -f "$PHPDOC_SOURCE_DIR/plugins/DummyPlugin.php" \
-t "$PHPDOC_TARGET_DIR" \
--title "$PHPDOC_TITLE"
echo

View file

@ -2,20 +2,35 @@
"name": "picocms/pico",
"type": "library",
"description": "Pico is a flat file CMS, this means there is no administration backend and database to deal with. You simply create .md files in the \"content\" folder and that becomes a page.",
"keywords": ["cms"],
"keywords": ["flat-file","cms","php","twig","markdown"],
"homepage": "http://picocms.org/",
"license": "MIT",
"authors": [
{
"name": "Gilbert Pellegrom",
"email": "gilbert@pellegrom.me"
"email": "gilbert@pellegrom.me",
"role": "Project Founder"
},
{
"name": "The Pico Community",
"homepage": "https://github.com/picocms/Pico/graphs/contributors",
"role": "Contributors"
}
],
"support": {
"docs": "http://picocms.org/docs",
"issues": "https://github.com/picocms/Pico/issues",
"source": "https://github.com/picocms/Pico"
},
"require": {
"php": ">=5.3.6",
"twig/twig": "1.18.*",
"erusev/parsedown-extra": "0.7.*",
"symfony/yaml" : "2.3"
"twig/twig": "^1.18",
"erusev/parsedown-extra": "^0.7",
"symfony/yaml" : "^2.3"
},
"require-dev" : {
"phpdocumentor/phpdocumentor": "^2.8",
"squizlabs/php_codesniffer": "^2.4"
},
"autoload": {
"psr-0": {

View file

@ -62,12 +62,18 @@ Instead of adding your own content to the `content-sample` folder, you should
create your own `content` directory in Pico's root directory. You can then add
and access your contents as described above.
As a common practice, we recommend you to separate your contents and assets
(like images, downloads etc.). We even deny access to your `content` directory
by default. So if you want to use a asset (e.g. a image) in one of your content
files, upload it to the (to be created) directory `assets` and use it as
follows: <code>!\[Image Title\](&#37;base_url&#37;/assets/image.png)</code>
### Text File Markup
Text files are marked up using [Markdown][]. They can also contain regular HTML.
At the top of text files you can place a block comment and specify certain
attributes of the page. For example:
At the top of text files you can place a block comment and specify certain meta
attributes of the page using [YAML][] (the "YAML header"). For example:
---
Title: Welcome
@ -290,6 +296,7 @@ setting `$config['rewrite_url'] = true;` in your `config/config.php`.
For more help have a look at the Pico documentation at http://picocms.org/docs.
[Markdown]: http://daringfireball.net/projects/markdown/syntax
[YAML]: https://en.wikipedia.org/wiki/YAML
[Twig]: http://twig.sensiolabs.org/documentation
[WikiThemes]: https://github.com/picocms/Pico/wiki/Pico-Themes
[WikiPlugins]: https://github.com/picocms/Pico/wiki/Pico-Plugins

View file

@ -1,6 +1,15 @@
<?php
<?php // @codingStandardsIgnoreFile
// load dependencies
if(is_file(__DIR__ . '/vendor/autoload.php')) {
// composer root package
require_once(__DIR__ . '/vendor/autoload.php');
} elseif(is_file(__DIR__ . '/../../../vendor/autoload.php')) {
// composer dependency package
require_once(__DIR__ . '/../../../vendor/autoload.php');
} else {
die("Cannot find `vendor/autoload.php`. Run `composer install`.");
}
// instance Pico
$pico = new Pico(

20
index.php.dist Normal file
View file

@ -0,0 +1,20 @@
<?php // @codingStandardsIgnoreFile
// check PHP version
if (version_compare(PHP_VERSION, '5.3.6', '<')) {
die('Pico requires PHP 5.3.6 or above to run');
}
// load dependencies
require_once(__DIR__ . '/vendor/autoload.php');
// instance Pico
$pico = new Pico(
__DIR__, // root dir
'config/', // config dir
'plugins/', // plugins dir
'themes/' // themes dir
);
// run application
echo $pico->run();

View file

@ -267,6 +267,7 @@ class Pico
* the rendered contents.
*
* @return string rendered Pico contents
* @throws RuntimeException thrown when a not recoverable error occurs
*/
public function run()
{
@ -281,6 +282,11 @@ class Pico
$this->loadConfig();
$this->triggerEvent('onConfigLoaded', array(&$this->config));
// check content dir
if (!is_dir($this->getConfig('content_dir'))) {
throw new RuntimeException('Invalid content directory "' . $this->getConfig('content_dir') . '"');
}
// evaluate request url
$this->evaluateRequestUrl();
$this->triggerEvent('onRequestUrl', array(&$this->requestUrl));
@ -446,6 +452,10 @@ class Pico
protected function loadConfig()
{
$config = null;
if (file_exists($this->getConfigDir() . 'config.php')) {
require($this->getConfigDir() . 'config.php');
}
$defaultConfig = array(
'site_title' => 'Pico',
'base_url' => '',
@ -460,11 +470,6 @@ class Pico
'timezone' => ''
);
$configFile = $this->getConfigDir() . 'config.php';
if (file_exists($configFile)) {
require $configFile;
}
$this->config = is_array($this->config) ? $this->config : array();
$this->config += is_array($config) ? $config + $defaultConfig : $defaultConfig;
@ -474,6 +479,10 @@ class Pico
$this->config['base_url'] = rtrim($this->config['base_url'], '/') . '/';
}
if ($this->config['rewrite_url'] === null) {
$this->config['rewrite_url'] = $this->isUrlRewritingEnabled();
}
if (empty($this->config['content_dir'])) {
// try to guess the content directory
if (is_dir($this->getRootDir() . 'content')) {
@ -558,9 +567,9 @@ class Pico
*
* We recommend you to use the `link` filter in templates to create
* internal links, e.g. `{{ "sub/page"|link }}` is equivalent to
* `{{ base_url }}sub/page`. In content files you can still use the
* `%base_url%` variable; e.g. `%base_url%?sub/page` will be automatically
* replaced accordingly.
* `{{ base_url }}/sub/page` and `{{ base_url }}?sub/page`, depending on
* enabled URL rewriting. In content files you can use the `%base_url%`
* variable; e.g. `%base_url%?sub/page` will be replaced accordingly.
*
* @see Pico::getRequestUrl()
* @return void
@ -578,6 +587,7 @@ class Pico
$pathComponent = substr($pathComponent, 0, $pathComponentLength);
}
$this->requestUrl = (strpos($pathComponent, '=') === false) ? rawurldecode($pathComponent) : '';
$this->requestUrl = trim($this->requestUrl, '/');
}
/**
@ -762,7 +772,7 @@ class Pico
$meta[$fieldId] = $meta[$fieldName];
unset($meta[$fieldName]);
}
} else {
} elseif (!isset($meta[$fieldId])) {
// guarantee array key existance
$meta[$fieldId] = '';
}
@ -776,10 +786,7 @@ class Pico
}
} else {
// guarantee array key existance
foreach ($headers as $id => $field) {
$meta[$id] = '';
}
$meta = array_fill_keys(array_keys($headers), '');
$meta['time'] = $meta['date_formatted'] = '';
}
@ -929,7 +936,7 @@ class Pico
$files = $this->getFiles($this->getConfig('content_dir'), $this->getConfig('content_ext'), Pico::SORT_NONE);
foreach ($files as $i => $file) {
// skip 404 page
if (basename($file) == '404' . $this->getConfig('content_ext')) {
if (basename($file) === '404' . $this->getConfig('content_ext')) {
unset($files[$i]);
continue;
}
@ -967,7 +974,7 @@ class Pico
'meta' => &$meta
);
if ($file == $this->requestFile) {
if ($file === $this->requestFile) {
$page['content'] = &$this->content;
}
@ -996,10 +1003,10 @@ class Pico
$bSortKey = (basename($b['id']) === 'index') ? dirname($b['id']) : $b['id'];
$cmp = strcmp($aSortKey, $bSortKey);
return $cmp * (($order == 'desc') ? -1 : 1);
return $cmp * (($order === 'desc') ? -1 : 1);
};
if ($this->getConfig('pages_order_by') == 'date') {
if ($this->getConfig('pages_order_by') === 'date') {
// sort by date
uasort($this->pages, function ($a, $b) use ($alphaSortClosure, $order) {
if (empty($a['time']) || empty($b['time'])) {
@ -1013,7 +1020,7 @@ class Pico
return $alphaSortClosure($a, $b);
}
return $cmp * (($order == 'desc') ? 1 : -1);
return $cmp * (($order === 'desc') ? 1 : -1);
});
} else {
// sort alphabetically
@ -1026,7 +1033,7 @@ class Pico
*
* @see Pico::readPages()
* @see Pico::sortPages()
* @return array|null the data of all pages
* @return array[]|null the data of all pages
*/
public function getPages()
{
@ -1053,7 +1060,7 @@ class Pico
if ($currentPageIndex !== false) {
$this->currentPage = &$this->pages[$currentPageId];
if (($this->getConfig('order_by') == 'date') && ($this->getConfig('order') == 'desc')) {
if (($this->getConfig('order_by') === 'date') && ($this->getConfig('order') === 'desc')) {
$previousPageOffset = 1;
$nextPageOffset = -1;
} else {
@ -1179,7 +1186,7 @@ class Pico
'prev_page' => $this->previousPage,
'current_page' => $this->currentPage,
'next_page' => $this->nextPage,
'is_front_page' => ($this->requestFile == $frontPage),
'is_front_page' => ($this->requestFile === $frontPage),
);
}
@ -1195,19 +1202,18 @@ class Pico
return $baseUrl;
}
if (
(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')
|| ($_SERVER['SERVER_PORT'] == 443)
|| (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
) {
$protocol = 'https';
} else {
$protocol = 'http';
if (!empty($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] !== 'off')) {
$protocol = 'https';
} elseif ($_SERVER['SERVER_PORT'] == 443) {
$protocol = 'https';
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')) {
$protocol = 'https';
}
$this->config['base_url'] =
$protocol . "://" . $_SERVER['HTTP_HOST']
. dirname($_SERVER['SCRIPT_NAME']) . '/';
. rtrim(dirname($_SERVER['SCRIPT_NAME']), '/') . '/';
return $this->getConfig('base_url');
}
@ -1219,13 +1225,13 @@ class Pico
*/
public function isUrlRewritingEnabled()
{
if (($this->getConfig('rewrite_url') === null) && isset($_SERVER['PICO_URL_REWRITING'])) {
return (bool) $_SERVER['PICO_URL_REWRITING'];
} elseif ($this->getConfig('rewrite_url')) {
return true;
$urlRewritingEnabled = $this->getConfig('rewrite_url');
if ($urlRewritingEnabled !== null) {
return $urlRewritingEnabled;
}
return false;
$this->config['rewrite_url'] = (isset($_SERVER['PICO_URL_REWRITING']) && $_SERVER['PICO_URL_REWRITING']);
return $this->getConfig('rewrite_url');
}
/**
@ -1294,7 +1300,7 @@ class Pico
* @param string $path relative or absolute path
* @return string absolute path
*/
protected function getAbsolutePath($path)
public function getAbsolutePath($path)
{
if (substr($path, 0, 1) !== '/') {
$path = $this->getRootDir() . $path;
@ -1320,8 +1326,7 @@ class Pico
if (!empty($this->plugins)) {
foreach ($this->plugins as $plugin) {
// only trigger events for plugins that implement PicoPluginInterface
// deprecated events (plugins for Pico 0.9 and older) will be
// triggered by the `PicoPluginDeprecated` plugin
// deprecated events (plugins for Pico 0.9 and older) will be triggered by `PicoDeprecated`
if (is_a($plugin, 'PicoPluginInterface')) {
$plugin->handleEvent($eventName, $params);
}

39
phpcs.xml Normal file
View file

@ -0,0 +1,39 @@
<?xml version="1.0"?>
<ruleset name="Pico">
<description>
Pico's coding standards mainly base on the PHP-FIG PSR-2 standard,
but without the MissingNamespace sniff.
</description>
<!--
Exclude build/ and vendor/ dirs as well as minified JavaScript files
-->
<exclude-pattern type="relative">^build/</exclude-pattern>
<exclude-pattern type="relative">^vendor/</exclude-pattern>
<exclude-pattern>*.min.js</exclude-pattern>
<!--
Check files for PHP syntax errors
-->
<config name="php_path" value="php"/>
<rule ref="Generic.PHP.Syntax"/>
<!--
Never use deprecated functions,
as they will be removed in future PHP releases
-->
<rule ref="Generic.PHP.DeprecatedFunctions"/>
<!--
Warn about structures which affect performance negatively
-->
<rule ref="Generic.CodeAnalysis.ForLoopWithTestFunctionCall"/>
<!--
Pico follows PHP-FIG PSR-2 Coding Style,
but doesn't use formal namespaces for historic reasons
-->
<rule ref="PSR2">
<exclude name="PSR1.Classes.ClassDeclaration.MissingNamespace"/>
</rule>
</ruleset>

View file

@ -67,7 +67,7 @@ class PicoDeprecated extends AbstractPicoPlugin
*
* @see DummyPlugin::onPluginsLoaded()
*/
public function onPluginsLoaded(&$plugins)
public function onPluginsLoaded(array &$plugins)
{
if (!empty($plugins)) {
foreach ($plugins as $plugin) {
@ -107,19 +107,17 @@ class PicoDeprecated extends AbstractPicoPlugin
* @see PicoDeprecated::loadRootDirConfig()
* @see PicoDeprecated::enablePlugins()
* @see DummyPlugin::onConfigLoaded()
* @param mixed[] &$realConfig array of config variables
* @param mixed[] &$config array of config variables
* @return void
*/
public function onConfigLoaded(&$realConfig)
public function onConfigLoaded(array &$config)
{
global $config;
$this->defineConstants();
$this->loadRootDirConfig($realConfig);
$this->loadRootDirConfig($config);
$this->enablePlugins();
$config = &$realConfig;
$GLOBALS['config'] = &$config;
$this->triggerEvent('config_loaded', array(&$realConfig));
$this->triggerEvent('config_loaded', array(&$config));
}
/**
@ -167,14 +165,22 @@ class PicoDeprecated extends AbstractPicoPlugin
* @param mixed[] &$realConfig array of config variables
* @return void
*/
protected function loadRootDirConfig(&$realConfig)
protected function loadRootDirConfig(array &$realConfig)
{
if (file_exists($this->getRootDir() . 'config.php')) {
// config.php in Pico::$rootDir is deprecated; use Pico::$configDir instead
// config.php in Pico::$rootDir is deprecated
// use config.php in Pico::$configDir instead
$config = null;
require($this->getRootDir() . 'config.php');
if (is_array($config)) {
if (isset($config['base_url'])) {
$config['base_url'] = rtrim($config['base_url'], '/') . '/';
}
if (isset($config['content_dir'])) {
$config['content_dir'] = rtrim($config['content_dir'], '/') . '/';
}
$realConfig = $config + $realConfig;
}
}
@ -276,7 +282,7 @@ class PicoDeprecated extends AbstractPicoPlugin
*
* @see DummyPlugin::onMetaHeaders()
*/
public function onMetaHeaders(&$headers)
public function onMetaHeaders(array &$headers)
{
$this->triggerEvent('before_read_file_meta', array(&$headers));
}
@ -286,7 +292,7 @@ class PicoDeprecated extends AbstractPicoPlugin
*
* @see DummyPlugin::onMetaParsed()
*/
public function onMetaParsed(&$meta)
public function onMetaParsed(array &$meta)
{
$this->triggerEvent('file_meta', array(&$meta));
}
@ -320,7 +326,7 @@ class PicoDeprecated extends AbstractPicoPlugin
*
* @see DummyPlugin::onSinglePageLoaded()
*/
public function onSinglePageLoaded(&$pageData)
public function onSinglePageLoaded(array &$pageData)
{
$this->triggerEvent('get_page_data', array(&$pageData, $pageData['meta']));
}
@ -336,8 +342,12 @@ class PicoDeprecated extends AbstractPicoPlugin
*
* @see DummyPlugin::onPagesLoaded()
*/
public function onPagesLoaded(&$pages, &$currentPage, &$previousPage, &$nextPage)
{
public function onPagesLoaded(
array &$pages,
array &$currentPage = null,
array &$previousPage = null,
array &$nextPage = null
) {
// remove keys of pages array
$plainPages = array();
foreach ($pages as &$pageData) {
@ -383,7 +393,7 @@ class PicoDeprecated extends AbstractPicoPlugin
*
* @see DummyPlugin::onPageRendering()
*/
public function onPageRendering(&$twig, &$twigVariables, &$templateName)
public function onPageRendering(Twig_Environment &$twig, array &$twigVariables, &$templateName)
{
// template name contains file extension since Pico 1.0
$fileExtension = '';

View file

@ -30,7 +30,7 @@ class PicoParsePagesContent extends AbstractPicoPlugin
*
* @see DummyPlugin::onSinglePageLoaded()
*/
public function onSinglePageLoaded(&$pageData)
public function onSinglePageLoaded(array &$pageData)
{
if (!isset($pageData['content'])) {
$pageData['content'] = $this->prepareFileContent($pageData['raw_content'], $pageData['meta']);

View file

@ -40,7 +40,7 @@ class PicoExcerpt extends AbstractPicoPlugin
*
* @see DummyPlugin::onConfigLoaded()
*/
public function onConfigLoaded(&$config)
public function onConfigLoaded(array &$config)
{
if (!isset($config['excerpt_length'])) {
$config['excerpt_length'] = 50;
@ -53,7 +53,7 @@ class PicoExcerpt extends AbstractPicoPlugin
* @see PicoExcerpt::createExcerpt()
* @see DummyPlugin::onSinglePageLoaded()
*/
public function onSinglePageLoaded(&$pageData)
public function onSinglePageLoaded(array &$pageData)
{
if (!isset($pageData['excerpt'])) {
$pageData['excerpt'] = $this->createExcerpt(

View file

@ -11,7 +11,7 @@
* @license http://opensource.org/licenses/MIT
* @version 1.0
*/
class DummyPlugin extends AbstractPicoPlugin
final class DummyPlugin extends AbstractPicoPlugin
{
/**
* This plugin is enabled by default?
@ -40,7 +40,7 @@ class DummyPlugin extends AbstractPicoPlugin
* @param object[] &$plugins loaded plugin instances
* @return void
*/
public function onPluginsLoaded(&$plugins)
public function onPluginsLoaded(array &$plugins)
{
// your code
}
@ -52,7 +52,7 @@ class DummyPlugin extends AbstractPicoPlugin
* @param mixed[] &$config array of config variables
* @return void
*/
public function onConfigLoaded(&$config)
public function onConfigLoaded(array &$config)
{
// your code
}
@ -141,7 +141,7 @@ class DummyPlugin extends AbstractPicoPlugin
* array key is later used to access the found value
* @return void
*/
public function onMetaHeaders(&$headers)
public function onMetaHeaders(array &$headers)
{
// your code
}
@ -155,7 +155,7 @@ class DummyPlugin extends AbstractPicoPlugin
* @param string[] &$headers known meta header fields
* @return void
*/
public function onMetaParsing(&$rawContent, &$headers)
public function onMetaParsing(&$rawContent, array &$headers)
{
// your code
}
@ -167,7 +167,7 @@ class DummyPlugin extends AbstractPicoPlugin
* @param string[] &$meta parsed meta data
* @return void
*/
public function onMetaParsed(&$meta)
public function onMetaParsed(array &$meta)
{
// your code
}
@ -249,7 +249,7 @@ class DummyPlugin extends AbstractPicoPlugin
* @param array &$pageData data of the loaded page
* @return void
*/
public function onSinglePageLoaded(&$pageData)
public function onSinglePageLoaded(array &$pageData)
{
// your code
}
@ -264,14 +264,18 @@ class DummyPlugin extends AbstractPicoPlugin
* @see Pico::getCurrentPage()
* @see Pico::getPreviousPage()
* @see Pico::getNextPage()
* @param array &$pages data of all known pages
* @param array &$currentPage data of the page being served
* @param array &$previousPage data of the previous page
* @param array &$nextPage data of the next page
* @param array[] &$pages data of all known pages
* @param array|null &$currentPage data of the page being served
* @param array|null &$previousPage data of the previous page
* @param array|null &$nextPage data of the next page
* @return void
*/
public function onPagesLoaded(&$pages, &$currentPage, &$previousPage, &$nextPage)
{
public function onPagesLoaded(
array &$pages,
array &$currentPage = null,
array &$previousPage = null,
array &$nextPage = null
) {
// your code
}
@ -295,7 +299,7 @@ class DummyPlugin extends AbstractPicoPlugin
* @param string &$templateName file name of the template
* @return void
*/
public function onPageRendering(&$twig, &$twigVariables, &$templateName)
public function onPageRendering(Twig_Environment &$twig, array &$twigVariables, &$templateName)
{
// your code
}

View file

@ -32,7 +32,7 @@ body {
}
table {
border-collapse: separate;
border-collapse: collapse;
border-spacing: 0;
}
@ -137,7 +137,7 @@ h3 {
margin-top: 2em;
}
p {
p, table {
margin-bottom: 1em;
}
@ -167,6 +167,17 @@ td, td img {
vertical-align: top;
}
td, th {
border: solid 1px #999;
padding: 0.25em 0.5em;
}
th {
font-weight: bold;
text-align: center;
background: #eee;
}
sub {
vertical-align: sub;
font-size: smaller;
@ -274,7 +285,6 @@ blockquote {
/* Small Devices, Tablets */
@media only screen and (max-width : 768px) {
.inner {
width: 85%;
}
@ -313,12 +323,10 @@ blockquote {
#header nav:hover ul {
display: block;
}
}
/* Extra Small Devices, Phones */
@media only screen and (max-width : 480px) {
.inner {
width: 85%;
}