diff --git a/.build/build.sh b/.build/build.sh new file mode 100755 index 0000000..b926661 --- /dev/null +++ b/.build/build.sh @@ -0,0 +1,309 @@ +#!/bin/bash +# PicoDeprecated -- build.sh +# Builds a new PicoDeprecated release and creates release archives. +# +# This file is part of Pico, a stupidly simple, blazing fast, flat file CMS. +# Visit us at https://picocms.org/ for more info. +# +# Copyright (c) 2019 Daniel Rudolf +# +# This work is licensed under the terms of the MIT license. +# For a copy, see LICENSE file or . +# +# SPDX-License-Identifier: MIT +# License-Filename: LICENSE + +set -eu -o pipefail +export LC_ALL=C + +# env variables +PHP="${PHP:-php}" +export -n PHP + +COMPOSER="${COMPOSER:-composer}" +export -n COMPOSER + +if ! which "$PHP" > /dev/null; then + echo "Missing script dependency: php" >&2 + exit 1 +elif ! which "$COMPOSER" > /dev/null; then + echo "Missing script dependency: composer" >&2 + exit 1 +elif ! which "git" > /dev/null; then + echo "Missing script dependency: git" >&2 + exit 1 +elif ! which "gh" > /dev/null; then + echo "Missing script dependency: gh" >&2 + exit 1 +elif ! which "rsync" > /dev/null; then + echo "Missing script dependency: rsync" >&2 + exit 1 +elif ! which "jq" > /dev/null; then + echo "Missing script dependency: jq" >&2 + exit 1 +fi + +# parameters +BUILD_NAME="pico-deprecated" +BUILD_PROJECT="picocms/pico-deprecated" +BUILD_VERSION= + +PICO_PROJECT="picocms/pico" + +PHP_VERSION="7.2" + +# options +VERSION= +PUBLISH= +NOCHECK= +NOCLEAN= + +while [ $# -gt 0 ]; do + if [ "$1" == "--help" ]; then + echo "Usage:" + echo " build.sh [OPTIONS]... [VERSION]" + echo + echo "Builds a new PicoDeprecated release and creates release archives." + echo + echo "Help options:" + echo " --help display this help and exit" + echo + echo "Application options:" + echo " --publish create GitHub release and upload artifacts" + echo " --no-check skip version checks for dev builds" + echo " --no-clean don't remove build dir on exit" + echo + echo "You must run this script from within PicoDeprecated's source directory." + echo "Please note that this script will perform a large number of strict sanity" + echo "checks before building a new non-development version of PicoDeprecated." + echo "VERSION must start with 'v'." + exit 0 + elif [ "$1" == "--publish" ]; then + PUBLISH="y" + shift + elif [ "$1" == "--no-check" ]; then + NOCHECK="y" + shift + elif [ "$1" == "--no-clean" ]; then + NOCLEAN="y" + shift + elif [ -z "$VERSION" ] && [ "${1:0:1}" == "v" ]; then + VERSION="$1" + shift + else + echo "Unknown option: $1" >&2 + exit 1 + fi +done + +# check options and current working dir +if [ ! -f "./composer.json" ] || [ ! -f "./PicoDeprecated.php" ]; then + echo "You must run this from within PicoDeprecated's source directory" >&2 + exit 1 +elif [ "$(git rev-parse --is-inside-work-tree 2> /dev/null)" != "true" ]; then + echo "You must run this from within a non-bare Git repository" >&2 + exit 1 +fi + +# parse version +function parse_version { + VERSION_FULL="${1#v}" + + if ! [[ "$VERSION_FULL" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(-([0-9A-Za-z\.\-]+))?(\+([0-9A-Za-z\.\-]+))?$ ]]; then + return 1 + fi + + VERSION_MAJOR="${BASH_REMATCH[1]}" + VERSION_MINOR="${BASH_REMATCH[2]}" + VERSION_PATCH="${BASH_REMATCH[3]}" + VERSION_SUFFIX="${BASH_REMATCH[5]}" + + VERSION_STABILITY="stable" + if [[ "$VERSION_SUFFIX" =~ ^(dev|a|alpha|b|beta|rc)?([.-]?[0-9]+)?([.-](dev))?$ ]]; then + if [ "${BASH_REMATCH[1]}" == "dev" ] || [ "${BASH_REMATCH[4]}" == "dev" ]; then + VERSION_STABILITY="dev" + elif [ "${BASH_REMATCH[1]}" == "a" ] || [ "${BASH_REMATCH[1]}" == "alpha" ]; then + VERSION_STABILITY="alpha" + elif [ "${BASH_REMATCH[1]}" == "b" ] || [ "${BASH_REMATCH[1]}" == "beta" ]; then + VERSION_STABILITY="beta" + elif [ "${BASH_REMATCH[1]}" == "rc" ]; then + VERSION_STABILITY="rc" + fi + fi +} + +export COMPOSER_ROOT_VERSION= + +BUILD_VERSION="v$("$PHP" -r 'class AbstractPicoPlugin {} require("./PicoDeprecated.php"); echo PicoDeprecated::VERSION;')" + +if ! parse_version "$BUILD_VERSION"; then + echo "Unable to build PicoDeprecated: Invalid PicoDeprecated version '$BUILD_VERSION'" >&2 + exit 1 +fi + +if [ -z "$VERSION" ]; then + GIT_LOCAL_HEAD="$(git rev-parse HEAD)" + GIT_LOCAL_BRANCH="$(git rev-parse --abbrev-ref HEAD)" + DATETIME="$(date -u +'%Y%m%dT%H%M%SZ')" + + VERSION="v$VERSION_MAJOR.$VERSION_MINOR.$VERSION_PATCH" + [ -z "$VERSION_SUFFIX" ] || VERSION+="-$VERSION_SUFFIX" + [ "$VERSION_STABILITY" == "dev" ] || VERSION+="-dev" + VERSION+="+git.$GIT_LOCAL_HEAD.$DATETIME" + + if ! parse_version "$VERSION"; then + echo "Unable to build PicoDeprecated: Invalid build version '$VERSION'" >&2 + exit 1 + fi + + COMPOSER_ROOT_VERSION="dev-$GIT_LOCAL_BRANCH" +else + if ! parse_version "$VERSION"; then + echo "Unable to build PicoDeprecated: Invalid build version '$VERSION'" >&2 + exit 1 + fi + + if [ "$VERSION_STABILITY" == "dev" ]; then + COMPOSER_ROOT_VERSION="$(jq -r --arg ALIAS "$VERSION_MAJOR.$VERSION_MINOR.x-dev" \ + '.extra."branch-alias"|to_entries|map(select(.value==$ALIAS).key)[0]//empty' \ + "composer.json")" + fi + + if [ -z "$COMPOSER_ROOT_VERSION" ]; then + COMPOSER_ROOT_VERSION="$VERSION_MAJOR.$VERSION_MINOR.$VERSION_PATCH" + [ -z "$VERSION_SUFFIX" ] || COMPOSER_ROOT_VERSION+="-$VERSION_SUFFIX" + [ "$VERSION_STABILITY" == "stable" ] || COMPOSER_ROOT_VERSION+="@$VERSION_STABILITY" + fi +fi + +# build checks +if [ "$VERSION_STABILITY" != "dev" ]; then + GIT_LOCAL_CLEAN="$(git status --porcelain)" + GIT_LOCAL_HEAD="$(git rev-parse HEAD)" + GIT_LOCAL_TAG="$(git rev-parse --verify "refs/tags/$VERSION" 2> /dev/null || true)" + GIT_REMOTE="$(git 'for-each-ref' --format='%(upstream:remotename)' "$(git symbolic-ref -q HEAD)")" + GIT_REMOTE_TAG="$(git ls-remote "${GIT_REMOTE:-origin}" "refs/tags/$VERSION" 2> /dev/null | cut -f 1 || true)" + PHP_VERSION_LOCAL="$("$PHP" -r 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;')" + + if [ "$VERSION" != "$BUILD_VERSION" ]; then + echo "Unable to build PicoDeprecated: Building $VERSION, but PicoDeprecated indicates $BUILD_VERSION" >&2 + exit 1 + elif [ -n "$GIT_LOCAL_CLEAN" ]; then + echo "Unable to build PicoDeprecated: Building $VERSION, but the working tree is not clean" >&2 + exit 1 + elif [ -z "$GIT_LOCAL_TAG" ]; then + echo "Unable to build PicoDeprecated: Building $VERSION, but no matching local Git tag was found" >&2 + exit 1 + elif [ "$GIT_LOCAL_HEAD" != "$GIT_LOCAL_TAG" ]; then + echo "Unable to build PicoDeprecated: Building $VERSION, but the matching Git tag is not checked out" >&2 + exit 1 + elif [ -z "$GIT_REMOTE_TAG" ]; then + echo "Unable to build PicoDeprecated: Building $VERSION, but no matching remote Git tag was found" >&2 + exit 1 + elif [ "$GIT_LOCAL_TAG" != "$GIT_REMOTE_TAG" ]; then + echo "Unable to build PicoDeprecated: Building $VERSION, but the matching local and remote Git tags differ" >&2 + exit 1 + elif [ "$PHP_VERSION_LOCAL" != "$PHP_VERSION" ]; then + echo "Unable to build PicoDeprecated: Refusing to build PicoDeprecated with PHP $PHP_VERSION_LOCAL, expecting PHP $PHP_VERSION" >&2 + exit 1 + fi +else + if [ -z "$NOCHECK" ] && [[ "$VERSION" != "$BUILD_VERSION"* ]]; then + echo "Unable to build PicoDeprecated: Building $VERSION, but PicoDeprecated indicates $BUILD_VERSION" >&2 + exit 1 + elif [ -n "$PUBLISH" ]; then + echo "Unable to build PicoDeprecated: Refusing to publish a dev version" >&2 + exit 1 + fi +fi + +# build in progress... +APP_DIR="$PWD" + +BUILD_DIR="$(mktemp -d)" +[ -n "$NOCLEAN" ] || trap "rm -rf ${BUILD_DIR@Q}" ERR EXIT + +echo "Building Pico $BUILD_VERSION ($VERSION)..." +[ -z "$NOCLEAN" ] || echo "Build directory: $BUILD_DIR" +echo + +# copy PicoDeprecated for building +# the working tree is always clean for non-dev versions, see build checks above +echo "Creating clean working tree copy of '$BUILD_PROJECT'..." +rsync -a \ + --exclude="/.build" \ + --exclude="/.git" \ + --exclude="/.github" \ + --exclude="/.gitattributes" \ + --exclude="/.gitignore" \ + --exclude="/.phpcs.xml" \ + --exclude-from=<(git ls-files --exclude-standard -oi --directory) \ + ./ "$BUILD_DIR/" + +echo + +# switch to build dir... +cd "$BUILD_DIR" + +# remove picocms/pico dependency +echo "Removing '$PICO_PROJECT' dependency..." +"$COMPOSER" remove --no-update "$PICO_PROJECT" +echo + +# set minimum stability +if [ "$VERSION_STABILITY" != "stable" ]; then + echo "Setting minimum stability to '$VERSION_STABILITY'..." + "$COMPOSER" config "minimum-stability" "$VERSION_STABILITY" + "$COMPOSER" config "prefer-stable" "true" + echo +fi + +# install dependencies +echo "Installing Composer dependencies..." +"$COMPOSER" install --no-dev --optimize-autoloader +echo + +# prepare release +echo "Removing '.git' directory..." +rm -rf .git + +echo "Removing '.git' directories of dependencies..." +find vendor/ -type d -path 'vendor/*/*/.git' -print0 | xargs -0 rm -rf + +echo + +# restore picocms/pico dependency +echo "Restoring '$PICO_PROJECT' dependency..." +"$COMPOSER" require --no-update "$PICO_PROJECT self.version" +echo + +# create release archives +ARCHIVE_FILENAME="$BUILD_NAME-release-$VERSION" + +echo "Creating release archive '$ARCHIVE_FILENAME.tar.gz'..." +find . -mindepth 1 -maxdepth 1 -printf '%f\0' \ + | xargs -0 -- tar -czf "$APP_DIR/$ARCHIVE_FILENAME.tar.gz" -- + +echo "Creating release archive '$ARCHIVE_FILENAME.zip'..." +zip -q -r "$APP_DIR/$ARCHIVE_FILENAME.zip" . + +# publish release +if [ -n "$PUBLISH" ]; then + echo + + # switch to app dir + cd "$APP_DIR" + + # create GitHub release and upload release archives + echo "Creating GitHub release and uploading release archives..." + + GITHUB_PRERELEASE= + [ "$VERSION_STABILITY" == "stable" ] || GITHUB_PRERELEASE="--prerelease" + + gh release create "$VERSION" \ + --title "Version $VERSION_FULL" \ + --generate-notes \ + "$GITHUB_PRERELEASE" \ + "$APP_DIR/$ARCHIVE_FILENAME.tar.gz" \ + "$APP_DIR/$ARCHIVE_FILENAME.zip" +fi diff --git a/.build/clean.sh b/.build/clean.sh deleted file mode 100755 index 0c44328..0000000 --- a/.build/clean.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -set -e - -[ -n "$PICO_BUILD_ENV" ] || { echo "No Pico build environment specified" >&2; exit 1; } - -# parameters -ARCHIVE_DIR="${1:-$PICO_PROJECT_DIR}" # directory to create release archives in - -# print parameters -echo "Cleaning up build environment..." -printf 'PICO_BUILD_DIR="%s"\n' "$PICO_BUILD_DIR" -printf 'ARCHIVE_DIR="%s"\n' "$ARCHIVE_DIR" -echo - -echo "Removing build directory..." -[ ! -d "$PICO_BUILD_DIR" ] || rm -rf "$PICO_BUILD_DIR" - -echo "Removing release archives..." -find "$ARCHIVE_DIR" -mindepth 1 -maxdepth 1 \ - \( -name 'pico-deprecated-release-*.tar.gz' -o -name 'pico-deprecated-release-*.zip' \) \ - -delete diff --git a/.build/init.sh.inc b/.build/init.sh.inc deleted file mode 100644 index 80828e7..0000000 --- a/.build/init.sh.inc +++ /dev/null @@ -1,7 +0,0 @@ -if [ -z "$PICO_BUILD_ENV" ]; then - echo "No Pico build environment specified" >&2 - exit 1 -fi - -# add project build dir to $PATH -export PATH="$PICO_PROJECT_DIR/.build:$PATH" diff --git a/.build/install.sh b/.build/install.sh deleted file mode 100755 index 59b89bb..0000000 --- a/.build/install.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -set -e - -[ -n "$PICO_BUILD_ENV" ] || { echo "No Pico build environment specified" >&2; exit 1; } - -# setup build system -"$PICO_TOOLS_DIR/setup/$PICO_BUILD_ENV.sh" --phpcs - -# install dependencies -echo "Running \`composer install\`..." -composer install --no-suggest diff --git a/.build/release.sh b/.build/release.sh deleted file mode 100755 index be64be3..0000000 --- a/.build/release.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bash -set -e - -[ -n "$PICO_BUILD_ENV" ] || { echo "No Pico build environment specified" >&2; exit 1; } - -# parameters -VERSION="${1:-$PROJECT_REPO_TAG}" # version to create a release for -ARCHIVE_DIR="${2:-$PICO_PROJECT_DIR}" # directory to create release archives in - -# print parameters -echo "Creating new release..." -printf 'VERSION="%s"\n' "$VERSION" -echo - -# set archive name -if [ -n "$VERSION" ]; then - ARCHIVE_NAME="pico-deprecated-release-v${VERSION#v}" -else - ARCHIVE_NAME="pico-deprecated-release-dev-${PROJECT_REPO_BRANCH:-master}" -fi - -# copy project -rsync -a \ - --exclude="/.git" \ - --exclude="/.build" \ - --exclude="/.github" \ - --exclude="/.gitattributes" \ - --exclude="/.gitignore" \ - --exclude="/.phpcs.xml" \ - --exclude="/.travis.yml" \ - --exclude="/pico-deprecated-release-v*.tar.gz" \ - --exclude="/pico-deprecated-release-v*.zip" \ - "$PICO_PROJECT_DIR/" \ - "$PICO_BUILD_DIR/" - -cd "$PICO_BUILD_DIR" - -# remove picocms/Pico dependency -echo "Removing 'picocms/pico' dependency..." -composer remove --no-update "picocms/pico" -echo - -# install dependencies -echo "Running \`composer install\`..." -composer install --no-suggest --prefer-dist --no-dev --optimize-autoloader -echo - -# create release archives -create-release.sh "$PICO_BUILD_DIR" "$ARCHIVE_DIR" "$ARCHIVE_NAME" diff --git a/.gitattributes b/.gitattributes index 0eacfff..1475def 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,4 +3,3 @@ /.gitattributes export-ignore /.gitignore export-ignore /.phpcs.xml export-ignore -/.travis.yml export-ignore diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 878d942..5ca512e 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,28 +1,33 @@ -name: "Mark or close stale issues and PRs" +name: Mark or close stale issues and PRs + on: - schedule: - - cron: "0 12 * * *" + schedule: + - cron: "0 */6 * * *" jobs: - stale: - runs-on: ubuntu-latest - steps: - - uses: actions/stale@v3 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - days-before-stale: 7 - days-before-close: 2 - stale-issue-message: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed in two days if no further activity - occurs. Thank you for your contributions! :+1: - stale-pr-message: > - This pull request has been automatically marked as stale because it has not had - recent activity. It will be closed in two days if no further activity - occurs. Thank you for your contributions! :+1: - stale-pr-label: "info: Stale" - stale-issue-label: "info: Stale" - exempt-issue-labels: "type: Bug,type: Enhancement,type: Feature,type: Idea,type: Release,info: Pinned" - exempt-pr-labels: "type: Bug,type: Enhancement,type: Feature,type: Idea,type: Release,info: Pinned" - remove-stale-when-updated: true + stale: + name: Mark or close stale issues and PRs + + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v3 + with: + days-before-stale: 7 + days-before-close: 2 + stale-issue-message: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed in two days if no further activity + occurs. Thank you for your contributions! :+1: + stale-pr-message: > + This pull request has been automatically marked as stale because it has not had + recent activity. It will be closed in two days if no further activity + occurs. Thank you for your contributions! :+1: + stale-pr-label: "info: Stale" + stale-issue-label: "info: Stale" + exempt-issue-labels: "type: Bug,type: Enhancement,type: Feature,type: Idea,type: Release,info: Pinned" + exempt-pr-labels: "type: Bug,type: Enhancement,type: Feature,type: Idea,type: Release,info: Pinned" + remove-stale-when-updated: true diff --git a/.github/workflows/test-pr.yml b/.github/workflows/test-pr.yml new file mode 100644 index 0000000..c6fd342 --- /dev/null +++ b/.github/workflows/test-pr.yml @@ -0,0 +1,27 @@ +name: Test PicoDeprecated pull request + +on: + pull_request: {} + +jobs: + test: + name: Test PicoDeprecated + uses: ./.github/workflows/test.yml + + bouncer: + name: Bouncer + + needs: test + if: ${{ always() }} + + runs-on: ubuntu-latest + permissions: {} + + steps: + - name: Check build matrix status + if: ${{ needs.test.result != 'success' }} + run: | + : + echo "Some tests of PicoDeprecated failed." >&2 + echo "Please check the GitHub workflow logs for details." >&2 + exit 1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..24b72f2 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,105 @@ +name: Test PicoDeprecated + +on: + push: + branches: + - 'master' + - 'pico-3.0' + tags: [ 'v*.*.*' ] + workflow_call: {} + +jobs: + test: + name: PHP ${{ matrix.PHP_VERSION }} + + runs-on: ubuntu-latest + permissions: + contents: read + + strategy: + matrix: + PHP_VERSION: + - '7.2' + - '7.3' + - '7.4' + - '8.0' + - '8.1' + - '8.2' + - '8.3' + - '8.4' + - '8.5' + - 'nightly' + fail-fast: false + + continue-on-error: ${{ matrix.PHP_VERSION == 'nightly' }} + + env: + PHP_VERSION: ${{ matrix.PHP_VERSION }} + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup PHP ${{ env.PHP_VERSION }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ env.PHP_VERSION }} + tools: composer, phpcs + + - name: Setup Composer auth + run: | + composer config --global github-oauth.github.com "${{ github.token }}" + + - name: Get Composer cache directory + run: | + COMPOSER_CACHE_DIR="$(composer config --global cache-dir)" + echo "COMPOSER_CACHE_DIR=$COMPOSER_CACHE_DIR" | tee -a "$GITHUB_ENV" + + - name: Restore Composer cache + uses: actions/cache@v5 + with: + path: ${{ env.COMPOSER_CACHE_DIR }} + key: ${{ runner.os }}-composer-php${{ env.PHP_VERSION }} + restore-keys: | + ${{ runner.os }}-composer- + + - name: Setup Composer root version + if: ${{ github.ref_type == 'branch' }} + run: | + COMPOSER_ROOT_VERSION= + + COMPOSER_ROOT_VERSION="$(composer config \ + extra.branch-alias."dev-${GITHUB_HEAD_REF:-$GITHUB_REF_NAME}" \ + 2> /dev/null || true)" + + if [ -z "$COMPOSER_ROOT_VERSION" ]; then + COMPOSER_ROOT_VERSION="$(php -r " + class AbstractPicoPlugin {} + require('./PicoDeprecated.php'); + echo preg_replace('/\.[0-9]+-dev$/', '.x-dev', PicoDeprecated::VERSION); + ")" + fi + + echo "COMPOSER_ROOT_VERSION=$COMPOSER_ROOT_VERSION" | tee -a "$GITHUB_ENV" + + - name: Install Composer dependencies + run: | + composer install + + - name: Read PicoDeprecated version + run: | + VERSION="$(php -r " + class AbstractPicoPlugin {} + require('./PicoDeprecated.php'); + echo PicoDeprecated::VERSION; + ")" + echo "VERSION=$VERSION" | tee -a "$GITHUB_ENV" + + - name: Check PicoDeprecated version + if: ${{ github.ref_type == 'tag' }} + run: | + [ "$GITHUB_REF_NAME" == "v$VERSION" ] + + - name: Run PHP_CodeSniffer + run: | + phpcs --standard=.phpcs.xml diff --git a/.gitignore b/.gitignore index 70ac336..e9e1e3e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,8 +15,5 @@ desktop.ini /vendor # Build system -/.build/build -/.build/deploy -/.build/ci-tools /pico-deprecated-release-*.tar.gz /pico-deprecated-release-*.zip diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e521bf8..0000000 --- a/.travis.yml +++ /dev/null @@ -1,65 +0,0 @@ -dist: trusty -sudo: false - -language: php - -cache: - directories: - - $HOME/.composer/cache/files - -jobs: - include: - # Test stage - - php: 5.3 - dist: precise - - php: 5.4 - - php: 5.5 - - php: 5.6 - - php: 7.0 - - php: 7.1 - - php: 7.2 - - php: 7.3 - - php: 7.4 - - php: nightly - - php: hhvm-3.27 # until Sep 2019 - - php: hhvm-3.30 # until Nov 2019 - - # Release deployment stage - - stage: deploy-release - if: tag IS present - php: 5.3 - dist: precise - install: - - install.sh - script: - - 'true' - before_deploy: - - release.sh "$PROJECT_REPO_TAG" - deploy: - provider: releases - api_key: ${GITHUB_OAUTH_TOKEN} - file: - - pico-deprecated-release-$PROJECT_REPO_TAG.tar.gz - - pico-deprecated-release-$PROJECT_REPO_TAG.zip - skip_cleanup: true - name: Version ${PROJECT_REPO_TAG:1} - draft: true - on: - tags: true - - # Ignore nightly build failures - allow_failures: - - php: nightly - fast_finish: true - -before_install: - - export PICO_TOOLS_DIR="$HOME/__picocms_tools" - - git clone --branch="$TOOLS_REPO_BRANCH" "https://github.com/$TOOLS_REPO_SLUG.git" "$PICO_TOOLS_DIR" - - . "$PICO_TOOLS_DIR/init/travis.sh.inc" - - . "$PICO_PROJECT_DIR/.build/init.sh.inc" - -install: - - install.sh - -script: - - phpcs --standard=.phpcs.xml "$PICO_PROJECT_DIR" diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cc5d1d..9ec2a00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,28 @@ Pico Deprecated Changelog because they are already listed in Pico's changelog. Only functional changes and/or BC-breaking changes are listed below. +### Version 3.0.0-beta.1 +Released: - + +``` +* [New] Update to API version 4 (no functional changes necessary) +* [New] Add new continous integration (CI) pipeline using GitHub Actions +* [New] Add new build script and Makefile to simplify PicoDeprecated's build + and release process; see Pico's `CONTRIBUTING.md` for details +* [New] Add `PicoDeprecated::VERSION` and `PicoDeprecated::VERSION_ID` + constants (similar to Pico's matching constants) +* [New] Add plugin and theme compatibility plugin for API version 3 +* [Changed] Enable PHP strict typing +* [Changed] ! Move classes to `\picocms\PicoDeprecated\…` PHP namespace +* [Fixed] Don't instantiate compatibility plugins multiple times +* [Fixed] Update Twig API usage to be compatible with Twig 3.3 +``` + +### Version 3.0.0-alpha.2 +Released: 2020-12-24 + +No changes + ### Version 2.1.4 Released: 2020-08-29 @@ -36,6 +58,13 @@ Released: 2020-04-10 No changes +### Version 3.0.0-alpha.1 +Released: 2020-03-29 + +``` +* [New] Kick-start development of Pico 3.0 +``` + ### Version 2.1.1 Released: 2019-12-31 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..82a1952 --- /dev/null +++ b/Makefile @@ -0,0 +1,55 @@ +# PicoDeprecated -- Makefile +# Makefile to build new PicoDeprecated releases using './.build/build.sh'. +# +# This file is part of Pico, a stupidly simple, blazing fast, flat file CMS. +# Visit us at https://picocms.org/ for more info. +# +# Copyright (c) 2022 Daniel Rudolf +# +# This work is licensed under the terms of the MIT license. +# For a copy, see LICENSE file or . +# +# SPDX-License-Identifier: MIT +# License-Filename: LICENSE + +version?= +nocheck?=false +publish=false + +php?=php +composer?=composer + +app_name=pico-deprecated +archive_tar=$(app_name)-release-*.tar.gz +archive_zip=$(app_name)-release-*.zip +export=$(app_name)-export.tar.gz + +all: clean build + +clean: clean-build clean-export + +clean-build: + find "." -name "$(archive_tar)" -exec rm -f {} \; + find "." -name "$(archive_zip)" -exec rm -f {} \; + +clean-export: + rm -f "./$(export)" + +build: export PHP=$(php) +build: export COMPOSER=$(composer) +build: + ./.build/build.sh$(if $(filter true,$(publish)), --publish,)$(if $(filter true,$(nocheck)), --no-check,)$(if $(version), "$(version)",) + +export: + git archive --prefix "$(app_name)/" -o "./$(export)" HEAD + +publish: publish=true +publish: build + +composer: + $(composer) install --optimize-autoloader --no-dev + +.PHONY: all \ + clean clean-build clean-export \ + build export publish \ + composer diff --git a/PicoDeprecated.php b/PicoDeprecated.php index 9334661..fea86a9 100644 --- a/PicoDeprecated.php +++ b/PicoDeprecated.php @@ -16,6 +16,12 @@ * License-Filename: LICENSE */ +declare(strict_types=1); + +use picocms\PicoDeprecated\Plugin\MainPlugin; +use picocms\PicoDeprecated\PluginApiPluginInterface; +use picocms\PicoDeprecated\PluginInterface; + /** * Maintain backward compatibility to older Pico releases * @@ -28,67 +34,88 @@ * API versions than the one of Pico's core, even when there was just the * slightest change. * - * {@see http://picocms.org/plugins/deprecated/} for a full list of features. + * {@see https://picocms.org/plugins/deprecated/} for a full list of features. * * @author Daniel Rudolf - * @link http://picocms.org - * @license http://opensource.org/licenses/MIT The MIT License - * @version 2.1 + * @link https://picocms.org + * @license https://opensource.org/licenses/MIT The MIT License + * @version 3.0 */ class PicoDeprecated extends AbstractPicoPlugin { + /** + * PicoDeprecated version + * + * @var string + */ + public const VERSION = '3.0.0-dev'; + + /** + * PicoDeprecated version ID + * + * @var int + */ + public const VERSION_ID = 30000; + /** * API version used by this plugin * * @var int */ - const API_VERSION = 3; + public const API_VERSION = 4; /** * API version 0, used by Pico 0.9 and earlier * * @var int */ - const API_VERSION_0 = 0; + public const API_VERSION_0 = 0; /** * API version 1, used by Pico 1.0 * * @var int */ - const API_VERSION_1 = 1; + public const API_VERSION_1 = 1; /** * API version 2, used by Pico 2.0 * * @var int */ - const API_VERSION_2 = 2; + public const API_VERSION_2 = 2; /** * API version 3, used by Pico 2.1 * * @var int */ - const API_VERSION_3 = 3; + public const API_VERSION_3 = 3; + + /** + * API version 4, used by Pico 3.0 + * + * @var int + */ + public const API_VERSION_4 = 4; /** * Loaded plugins, indexed by API version * * @see PicoDeprecated::getPlugins() * - * @var object[] + * @var object[][] */ - protected $plugins = array(); + protected $plugins = []; /** * Loaded compatibility plugins * * @see PicoDeprecated::getCompatPlugins() * - * @var PicoCompatPluginInterface[] + * @var PluginInterface[] */ - protected $compatPlugins = array(); + protected $compatPlugins = []; /** * {@inheritDoc} @@ -101,18 +128,24 @@ public function __construct(Pico $pico) require(__DIR__ . '/vendor/autoload.php'); } - if (!class_exists('PicoMainCompatPlugin')) { - die( - "Cannot find PicoDeprecated's 'vendor/autoload.php'. If you're using a composer-based Pico install, " + if (!class_exists(MainPlugin::class)) { + throw new RuntimeException( + "Cannot find PicoDeprecated's 'vendor/autoload.php'. If you're using a Composer-based Pico install, " . "run `composer update`. If you're rather trying to use one of PicoDeprecated's pre-built release " . "packages, make sure to download PicoDeprecated's release package matching Pico's version named " - . "'pico-deprecated-release-v*.tar.gz' (don't download a source code package)." + . "'pico-deprecated-release-v*.tar.gz'; make sure not to download a source code package." ); } - if ($pico::API_VERSION !== static::API_VERSION) { + if ($pico::VERSION_ID !== self::VERSION_ID) { throw new RuntimeException( - 'PicoDeprecated requires API version ' . static::API_VERSION . ', ' + 'PicoDeprecated v' . self::VERSION . ' is incompatible with Pico v' . $pico::VERSION + ); + } + + if ($pico::API_VERSION !== self::API_VERSION) { + throw new RuntimeException( + 'PicoDeprecated requires API version ' . self::API_VERSION . ', ' . 'but Pico is running API version ' . $pico::API_VERSION ); } @@ -130,10 +163,10 @@ public function handleEvent($eventName, array $params) $isCoreEvent = in_array($eventName, $this->getCoreEvents()); foreach ($this->compatPlugins as $plugin) { if ($isCoreEvent) { - if ($plugin->getApiVersion() === static::API_VERSION) { + if ($plugin->getApiVersion() === self::API_VERSION) { $plugin->handleEvent($eventName, $params); } - } elseif ($plugin instanceof PicoPluginApiCompatPluginInterface) { + } elseif ($plugin instanceof PluginApiPluginInterface) { $plugin->handleCustomEvent($eventName, $params); } } @@ -148,15 +181,15 @@ public function handleEvent($eventName, array $params) * * @param object[] $plugins loaded plugin instances */ - public function onPluginsLoaded(array $plugins) + public function onPluginsLoaded(array $plugins): void { - $this->loadCompatPlugin('PicoMainCompatPlugin'); + $this->loadCompatPlugin(MainPlugin::class); foreach ($plugins as $plugin) { $this->loadPlugin($plugin); } - $this->getPico()->triggerEvent('onPicoDeprecated', array($this)); + $this->getPico()->triggerEvent('onPicoDeprecated', [ $this ]); } /** @@ -167,7 +200,7 @@ public function onPluginsLoaded(array $plugins) * * @param object $plugin loaded plugin instance */ - public function onPluginManuallyLoaded($plugin) + public function onPluginManuallyLoaded(object $plugin): void { $this->loadPlugin($plugin); } @@ -179,7 +212,7 @@ public function onPluginManuallyLoaded($plugin) * @param int $themeApiVersion API version of the theme * @param array $themeConfig config array of the theme */ - public function onThemeLoaded($theme, $themeApiVersion, array &$themeConfig) + public function onThemeLoaded(string $theme, int $themeApiVersion, array &$themeConfig): void { $this->loadThemeApiCompatPlugin($themeApiVersion); } @@ -193,13 +226,13 @@ public function onThemeLoaded($theme, $themeApiVersion, array &$themeConfig) * * @param object $plugin loaded plugin instance */ - protected function loadPlugin($plugin) + protected function loadPlugin(object $plugin): void { $pluginName = get_class($plugin); $apiVersion = $this->getPluginApiVersion($plugin); if (!isset($this->plugins[$apiVersion])) { - $this->plugins[$apiVersion] = array(); + $this->plugins[$apiVersion] = []; $this->loadPluginApiCompatPlugin($apiVersion); } @@ -213,23 +246,27 @@ protected function loadPlugin($plugin) * * @return object[] loaded plugin instances */ - public function getPlugins($apiVersion) + public function getPlugins(int $apiVersion): array { - return isset($this->plugins[$apiVersion]) ? $this->plugins[$apiVersion] : array(); + return $this->plugins[$apiVersion] ?? []; } /** * Loads a compatibility plugin * - * @param PicoCompatPluginInterface|string $plugin either the class name of - * a plugin to instantiate or a plugin instance + * @param PluginInterface|string $plugin either the class name of a plugin + * to instantiate or a plugin instance * - * @return PicoCompatPluginInterface instance of the loaded plugin + * @return PluginInterface instance of the loaded plugin */ - public function loadCompatPlugin($plugin) + public function loadCompatPlugin($plugin): PluginInterface { if (!is_object($plugin)) { $className = (string) $plugin; + if (isset($this->compatPlugins[$className])) { + return $this->compatPlugins[$className]; + } + if (class_exists($className)) { $plugin = new $className($this->getPico(), $this); } else { @@ -244,10 +281,10 @@ public function loadCompatPlugin($plugin) return $this->compatPlugins[$className]; } - if (!($plugin instanceof PicoCompatPluginInterface)) { + if (!($plugin instanceof PluginInterface)) { throw new RuntimeException( "Unable to load PicoDeprecated compatibility plugin '" . $className . "': " - . "Compatibility plugins must implement 'PicoCompatPluginInterface'" + . "Compatibility plugins must implement '" . PluginInterface::class . "'" ); } @@ -269,10 +306,10 @@ public function loadCompatPlugin($plugin) * * @param int $apiVersion API version to load the compatibility plugin for */ - protected function loadPluginApiCompatPlugin($apiVersion) + protected function loadPluginApiCompatPlugin(int $apiVersion): void { - if ($apiVersion !== static::API_VERSION) { - $this->loadCompatPlugin('PicoPluginApi' . $apiVersion . 'CompatPlugin'); + if ($apiVersion !== self::API_VERSION) { + $this->loadCompatPlugin('picocms\PicoDeprecated\Plugin\PluginApi' . $apiVersion . 'Plugin'); } } @@ -281,19 +318,19 @@ protected function loadPluginApiCompatPlugin($apiVersion) * * @param int $apiVersion API version to load the compatibility plugin for */ - protected function loadThemeApiCompatPlugin($apiVersion) + protected function loadThemeApiCompatPlugin(int $apiVersion): void { - if ($apiVersion !== static::API_VERSION) { - $this->loadCompatPlugin('PicoThemeApi' . $apiVersion . 'CompatPlugin'); + if ($apiVersion !== self::API_VERSION) { + $this->loadCompatPlugin('picocms\PicoDeprecated\Plugin\ThemeApi' . $apiVersion . 'Plugin'); } } /** * Returns all loaded compatibility plugins * - * @return PicoCompatPluginInterface[] list of loaded compatibility plugins + * @return PluginInterface[] list of loaded compatibility plugins */ - public function getCompatPlugins() + public function getCompatPlugins(): array { return $this->compatPlugins; } @@ -313,7 +350,7 @@ public function getCompatPlugins() * @param string $eventName event to trigger * @param array $params optional parameters to pass */ - public function triggerEvent($apiVersion, $eventName, array $params = array()) + public function triggerEvent(int $apiVersion, string $eventName, array $params = []): void { foreach ($this->getPlugins($apiVersion) as $plugin) { $plugin->handleEvent($eventName, $params); @@ -327,7 +364,7 @@ public function triggerEvent($apiVersion, $eventName, array $params = array()) * * @return int API version used by the plugin */ - public function getPluginApiVersion($plugin) + public function getPluginApiVersion(object $plugin): int { $pluginApiVersion = self::API_VERSION_0; if ($plugin instanceof PicoPluginInterface) { @@ -345,9 +382,9 @@ public function getPluginApiVersion($plugin) * * @return string[] list of Pico's core events */ - public function getCoreEvents() + public function getCoreEvents(): array { - return array( + return [ 'onPluginsLoaded', 'onPluginManuallyLoaded', 'onConfigLoaded', @@ -377,7 +414,7 @@ public function getCoreEvents() 'onMetaHeaders', 'onYamlParserRegistered', 'onParsedownRegistered', - 'onTwigRegistered' - ); + 'onTwigRegistered', + ]; } } diff --git a/README.md b/README.md index 4c3091a..7378db9 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Pico Deprecated Plugin This is the repository of Pico's official `PicoDeprecated` plugin. -Pico is a stupidly simple, blazing fast, flat file CMS. See http://picocms.org/ for more info. +Pico is a stupidly simple, blazing fast, flat file CMS. See https://picocms.org/ for more info. `PicoDeprecated`'s purpose is to maintain backward compatibility to older versions of Pico, by re-introducing characteristics that were removed from Pico's core. It for example triggers old events (like the `before_render` event used before Pico 1.0) and reads config files that were written in PHP (`config/config.php`, used before Pico 2.0). @@ -27,9 +27,9 @@ Usage You can explicitly disable `PicoDeprecated` by adding `PicoDeprecated.enabled: false` to your `config/config.yml`. If you want to re-enable `PicoDeprecated`, simply remove this line from your `config/config.yml`. `PicoDeprecated` itself has no configuration options, it enables and disables all of its features depending on whether there are plugins and/or themes requiring said characteristics. -`PicoDeprecated`'s functionality is split into various so-called "compatibility plugins". There are compatibility plugins for every old API version (Pico 0.9 and earlier were using API version 0, Pico 1.0 was using API version 1 and Pico 2.0 was using API version 2; the current API version is version 3, used by Pico 2.1), one for plugins and another one for themes. Their purpose is to re-introduce characteristics plugins and themes using said API version might rely on. For example, plugin API compatibility plugins are responsible for simulating old Pico core events (like the `before_render` event used by Pico 0.9 and earlier). Theme API compatibility plugins will e.g. register old Twig variables (like the `is_front_page` Twig variable used by Pico 1.0). If you install a plugin using API version 2, the corresponding `PicoPluginApi2CompatPlugin` will be loaded. All plugin API compatibility plugins also depend on their theme counterpart, thus `PicoThemeApi2CompatPlugin` will be loaded, too. Furthermore all compatibility plugins depend on their respective API successors. +`PicoDeprecated`'s functionality is split into various so-called "compatibility plugins". There are compatibility plugins for every old API version (Pico 0.9 and earlier were using API version 0, Pico 1.0 was using API version 1 and Pico 2.0 was using API version 2; the current API version is version 3, used by Pico 2.1), one for plugins and another one for themes. Their purpose is to re-introduce characteristics plugins and themes using said API version might rely on. For example, plugin API compatibility plugins are responsible for simulating old Pico core events (like the `before_render` event used by Pico 0.9 and earlier). Theme API compatibility plugins will e.g. register old Twig variables (like the `is_front_page` Twig variable used by Pico 1.0). If you install a plugin using API version 2, the corresponding `picocms\PicoDeprecated\Plugin\PluginApi2Plugin` will be loaded. All plugin API compatibility plugins also depend on their theme counterpart, thus `picocms\PicoDeprecated\Plugin\ThemeApi2Plugin` will be loaded, too. Furthermore all compatibility plugins depend on their respective API successors. -The plugin exposes a simple API to allow other plugins to load their own compatibility plugins. As a plugin developer you may use the `PicoDeprecated::loadCompatPlugin(PicoCompatPluginInterface $compatPlugin)` method to load a custom compatibility plugin. Use `PicoDeprecated::getCompatPlugins()` to return a list of all loaded compatibility plugins. You can furthermore use the `PicoDeprecated::getPlugins(int $apiVersion)` method to return a list of all loaded Pico plugins using a particular API version. If you want to trigger a custom event on plugins using a particular API version only, use `PicoDeprecated::triggerEvent(int $apiVersion, string $eventName, array $parameters = [])`. `PicoDeprecated` furthermore triggers the custom `onPicoDeprecated(PicoDeprecated $picoDeprecated)` event. +The plugin exposes a simple API to allow other plugins to load their own compatibility plugins. As a plugin developer you may use the `PicoDeprecated::loadCompatPlugin(picocms\PicoDeprecated\PluginInterface $compatPlugin)` method to load a custom compatibility plugin. Use `PicoDeprecated::getCompatPlugins()` to return a list of all loaded compatibility plugins. You can furthermore use the `PicoDeprecated::getPlugins(int $apiVersion)` method to return a list of all loaded Pico plugins using a particular API version. If you want to trigger a custom event on plugins using a particular API version only, use `PicoDeprecated::triggerEvent(int $apiVersion, string $eventName, array $parameters = [])`. `PicoDeprecated` furthermore triggers the custom `onPicoDeprecated(PicoDeprecated $picoDeprecated)` event. Getting Help ------------ diff --git a/composer.json b/composer.json index daf56bc..6e894d8 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "type": "pico-plugin", "description": "This is Pico's official PicoDeprecated plugin. Pico is a stupidly simple, blazing fast, flat file CMS.", "keywords": [ "pico", "picocms", "picocms-plugin", "pico-deprecated", "compatibility", "deprecation" ], - "homepage": "http://picocms.org/", + "homepage": "https://picocms.org/", "license": "MIT", "authors": [ { @@ -13,7 +13,7 @@ }, { "name": "The Pico Community", - "homepage": "http://picocms.org/" + "homepage": "https://picocms.org/" }, { "name": "Contributors", @@ -21,16 +21,20 @@ } ], "support": { - "docs": "http://picocms.org/plugins/deprecated/", + "docs": "https://picocms.org/plugins/deprecated/", "issues": "https://github.com/picocms/pico-deprecated/issues", "source": "https://github.com/picocms/pico-deprecated" }, "require": { - "php": ">=5.3.0", + "php": ">=7.2.5", "picocms/pico": "self.version" }, "autoload": { - "classmap": [ "PicoDeprecated.php", "lib/", "plugins/" ] + "psr-0": { "PicoDeprecated": "" }, + "psr-4": { + "picocms\\PicoDeprecated\\": "lib/", + "picocms\\PicoDeprecated\\Plugin\\": "plugins/" + } }, "extra": { "branch-alias": { diff --git a/lib/AbstractPicoCompatPlugin.php b/lib/AbstractPlugin.php similarity index 64% rename from lib/AbstractPicoCompatPlugin.php rename to lib/AbstractPlugin.php index 1d3961a..80804f7 100644 --- a/lib/AbstractPicoCompatPlugin.php +++ b/lib/AbstractPlugin.php @@ -4,32 +4,39 @@ * in the version control history of the file, available from the following * original location: * - * + * * * SPDX-License-Identifier: MIT * License-Filename: LICENSE */ +declare(strict_types=1); + +namespace picocms\PicoDeprecated; + +use Pico; +use PicoDeprecated; + /** * Abstract class to extend from when implementing a PicoDeprecated * compatibility plugin * - * Please refer to {@see PicoCompatPluginInterface} for more information about - * how to develop a PicoDeprecated compatibility plugin. + * Please refer to {@see PicoPluginInterface} for more information about how to + * develop a PicoDeprecated compatibility plugin. * - * @see PicoCompatPluginInterface + * @see PicoPluginInterface * * @author Daniel Rudolf - * @link http://picocms.org - * @license http://opensource.org/licenses/MIT The MIT License - * @version 2.1 + * @link https://picocms.org + * @license https://opensource.org/licenses/MIT The MIT License + * @version 3.0 */ -abstract class AbstractPicoCompatPlugin implements PicoCompatPluginInterface +abstract class AbstractPlugin implements PluginInterface { /** * Current instance of Pico * - * @see PicoCompatPluginInterface::getPico() + * @see PicoPluginInterface::getPico() * * @var Pico */ @@ -38,7 +45,7 @@ abstract class AbstractPicoCompatPlugin implements PicoCompatPluginInterface /** * Instance of the main PicoDeprecated plugin * - * @see PicoCompatPluginInterface::getPicoDeprecated() + * @see PluginInterface::getPicoDeprecated() * * @var PicoDeprecated */ @@ -47,11 +54,11 @@ abstract class AbstractPicoCompatPlugin implements PicoCompatPluginInterface /** * List of plugins which this plugin depends on * - * @see PicoCompatPluginInterface::getDependencies() + * @see PicoPluginInterface::getDependencies() * * @var string[] */ - protected $dependsOn = array(); + protected $dependsOn = []; /** * Constructs a new instance of a PicoDeprecated compatibility plugin @@ -68,17 +75,17 @@ public function __construct(Pico $pico, PicoDeprecated $picoDeprecated) /** * {@inheritDoc} */ - public function handleEvent($eventName, array $params) + public function handleEvent(string $eventName, array $params): void { if (method_exists($this, $eventName)) { - call_user_func_array(array($this, $eventName), $params); + call_user_func_array([ $this, $eventName ], $params); } } /** * {@inheritDoc} */ - public function getPico() + public function getPico(): Pico { return $this->pico; } @@ -86,7 +93,7 @@ public function getPico() /** * {@inheritDoc} */ - public function getPicoDeprecated() + public function getPicoDeprecated(): PicoDeprecated { return $this->picoDeprecated; } @@ -94,7 +101,7 @@ public function getPicoDeprecated() /** * {@inheritDoc} */ - public function getDependencies() + public function getDependencies(): array { return (array) $this->dependsOn; } diff --git a/lib/AbstractPicoPluginApiCompatPlugin.php b/lib/AbstractPluginApiPlugin.php similarity index 70% rename from lib/AbstractPicoPluginApiCompatPlugin.php rename to lib/AbstractPluginApiPlugin.php index af32b2f..96cf1ee 100644 --- a/lib/AbstractPicoPluginApiCompatPlugin.php +++ b/lib/AbstractPluginApiPlugin.php @@ -4,42 +4,45 @@ * in the version control history of the file, available from the following * original location: * - * + * * * SPDX-License-Identifier: MIT * License-Filename: LICENSE */ +declare(strict_types=1); + +namespace picocms\PicoDeprecated; + /** * Abstract class to extend from when implementing a PicoDeprecated plugin API * compatibility plugin * - * Please refer to {@see PicoPluginApiCompatPluginInterface} for more information about - * how to develop a PicoDeprecated plugin API compatibility plugin. + * Please refer to {@see PluginApiPluginInterface} for more information about how to + * develop a PicoDeprecated plugin API compatibility plugin. * - * @see PicoPluginApiCompatPluginInterface + * @see PluginApiPluginInterface * * @author Daniel Rudolf - * @link http://picocms.org - * @license http://opensource.org/licenses/MIT The MIT License - * @version 2.1 + * @link https://picocms.org + * @license https://opensource.org/licenses/MIT The MIT License + * @version 3.0 */ -abstract class AbstractPicoPluginApiCompatPlugin extends AbstractPicoCompatPlugin implements - PicoPluginApiCompatPluginInterface +abstract class AbstractPluginApiPlugin extends AbstractPlugin implements PluginApiPluginInterface { /** * Map of core events matching event signatures of older API versions * - * @see AbstractPicoPluginApiCompatPlugin::handleEvent() + * @see AbstractPluginApiPlugin::handleEvent() * * @var array */ - protected $eventAliases = array(); + protected $eventAliases = []; /** * {@inheritDoc} */ - public function handleEvent($eventName, array $params) + public function handleEvent(string $eventName, array $params): void { parent::handleEvent($eventName, $params); @@ -54,7 +57,7 @@ public function handleEvent($eventName, array $params) /** * {@inheritDoc} */ - public function handleCustomEvent($eventName, array $params = array()) + public function handleCustomEvent(string $eventName, array $params = []): void { $this->getPicoDeprecated()->triggerEvent($this->getApiVersionSupport(), $eventName, $params); } @@ -65,7 +68,7 @@ public function handleCustomEvent($eventName, array $params = array()) * @param string $eventName name of the event to trigger * @param array $params optional parameters to pass */ - protected function triggerEvent($eventName, array $params = array()) + protected function triggerEvent(string $eventName, array $params = []): void { $apiVersion = $this->getApiVersionSupport(); $picoDeprecated = $this->getPicoDeprecated(); diff --git a/lib/PicoPluginApiCompatPluginInterface.php b/lib/PluginApiPluginInterface.php similarity index 65% rename from lib/PicoPluginApiCompatPluginInterface.php rename to lib/PluginApiPluginInterface.php index 5e71768..f2f9787 100644 --- a/lib/PicoPluginApiCompatPluginInterface.php +++ b/lib/PluginApiPluginInterface.php @@ -4,21 +4,25 @@ * in the version control history of the file, available from the following * original location: * - * + * * * SPDX-License-Identifier: MIT * License-Filename: LICENSE */ +declare(strict_types=1); + +namespace picocms\PicoDeprecated; + /** * Common interface for PicoDeprecated plugin API compatibility plugins * * @author Daniel Rudolf - * @link http://picocms.org - * @license http://opensource.org/licenses/MIT The MIT License - * @version 2.1 + * @link https://picocms.org + * @license https://opensource.org/licenses/MIT The MIT License + * @version 3.0 */ -interface PicoPluginApiCompatPluginInterface extends PicoCompatPluginInterface +interface PluginApiPluginInterface extends PluginInterface { /** * Handles custom events for plugins of the supported API version @@ -26,12 +30,12 @@ interface PicoPluginApiCompatPluginInterface extends PicoCompatPluginInterface * @param string $eventName name of the triggered event * @param array $params passed parameters */ - public function handleCustomEvent($eventName, array $params = array()); + public function handleCustomEvent(string $eventName, array $params = []): void; /** * Returns the API version this plugin maintains backward compatibility for * * @return int */ - public function getApiVersionSupport(); + public function getApiVersionSupport(): int; } diff --git a/lib/PicoCompatPluginInterface.php b/lib/PluginInterface.php similarity index 70% rename from lib/PicoCompatPluginInterface.php rename to lib/PluginInterface.php index 6ede84f..cdf751b 100644 --- a/lib/PicoCompatPluginInterface.php +++ b/lib/PluginInterface.php @@ -4,21 +4,28 @@ * in the version control history of the file, available from the following * original location: * - * + * * * SPDX-License-Identifier: MIT * License-Filename: LICENSE */ +declare(strict_types=1); + +namespace picocms\PicoDeprecated; + +use Pico; +use PicoDeprecated; + /** * Common interface for PicoDeprecated compatibility plugins * * @author Daniel Rudolf - * @link http://picocms.org - * @license http://opensource.org/licenses/MIT The MIT License - * @version 2.1 + * @link https://picocms.org + * @license https://opensource.org/licenses/MIT The MIT License + * @version 3.0 */ -interface PicoCompatPluginInterface +interface PluginInterface { /** * Handles a Pico event @@ -26,14 +33,14 @@ interface PicoCompatPluginInterface * @param string $eventName name of the triggered event * @param array $params passed parameters */ - public function handleEvent($eventName, array $params); + public function handleEvent(string $eventName, array $params): void; /** * Returns a list of names of compat plugins required by this plugin * * @return string[] required plugins */ - public function getDependencies(); + public function getDependencies(): array; /** * Returns the plugin's instance of Pico @@ -42,7 +49,7 @@ public function getDependencies(); * * @return Pico the plugin's instance of Pico */ - public function getPico(); + public function getPico(): Pico; /** * Returns the plugin's main PicoDeprecated plugin instance @@ -51,12 +58,12 @@ public function getPico(); * * @return PicoDeprecated the plugin's instance of Pico */ - public function getPicoDeprecated(); + public function getPicoDeprecated(): PicoDeprecated; /** * Returns the version of the API this plugin uses * * @return int the API version used by this plugin */ - public function getApiVersion(); + public function getApiVersion(): int; } diff --git a/plugins/PicoMainCompatPlugin.php b/plugins/MainPlugin.php similarity index 81% rename from plugins/PicoMainCompatPlugin.php rename to plugins/MainPlugin.php index 683aad9..2919950 100644 --- a/plugins/PicoMainCompatPlugin.php +++ b/plugins/MainPlugin.php @@ -4,7 +4,7 @@ * in the version control history of the file, available from the following * original location: * - * + * * * This file was created by splitting up an original file into multiple files, * which in turn was previously part of the project's main repository. The @@ -18,15 +18,23 @@ * License-Filename: LICENSE */ +declare(strict_types=1); + +namespace picocms\PicoDeprecated\Plugin; + +use picocms\PicoDeprecated\AbstractPlugin; +use PicoDeprecated; +use ReflectionObject; + /** * Maintains backward compatibility with older Pico versions * * @author Daniel Rudolf - * @link http://picocms.org - * @license http://opensource.org/licenses/MIT The MIT License - * @version 2.1 + * @link https://picocms.org + * @license https://opensource.org/licenses/MIT The MIT License + * @version 3.0 */ -class PicoMainCompatPlugin extends AbstractPicoCompatPlugin +class MainPlugin extends AbstractPlugin { /** * Load's config.php from Pico's root and config dir @@ -36,11 +44,11 @@ class PicoMainCompatPlugin extends AbstractPicoCompatPlugin * {@see Pico::loadConfig()}. `onConfigLoaded` is triggered later, thus we * use the `onPluginsLoaded` event. * - * @see PicoMainCompatPlugin::loadScriptedConfig() + * @see MainPlugin::loadScriptedConfig() * * @param object[] $plugins loaded plugin instances */ - public function onPluginsLoaded(array $plugins) + public function onPluginsLoaded(array $plugins): void { // deprecated since Pico 1.0 if (is_file($this->getPico()->getRootDir() . 'config.php')) { @@ -62,21 +70,18 @@ public function onPluginsLoaded(array $plugins) * solution. Otherwise we'd have to copy all of Pico's code dealing with * special config settings (like making paths and URLs absolute). * - * @see PicoMainCompatPlugin::onConfigLoaded() + * @see MainPlugin::onConfigLoaded() * @see Pico::loadConfig() * * @param string $configFile path to the config file to load */ - protected function loadScriptedConfig($configFile) + protected function loadScriptedConfig(string $configFile): void { // scope isolated require() - $includeConfigClosure = function ($configFile) { + $includeConfigClosure = static function ($configFile) { require($configFile); - return (isset($config) && is_array($config)) ? $config : array(); + return (isset($config) && is_array($config)) ? $config : []; }; - if (PHP_VERSION_ID >= 50400) { - $includeConfigClosure = $includeConfigClosure->bindTo(null); - } $scriptedConfig = $includeConfigClosure($configFile); @@ -85,7 +90,7 @@ protected function loadScriptedConfig($configFile) $picoConfigReflector = $picoReflector->getProperty('config'); $picoConfigReflector->setAccessible(true); - $config = $picoConfigReflector->getValue($this->getPico()) ?: array(); + $config = $picoConfigReflector->getValue($this->getPico()) ?: []; $config += $scriptedConfig; $picoConfigReflector->setValue($this->getPico(), $config); @@ -95,8 +100,8 @@ protected function loadScriptedConfig($configFile) /** * {@inheritDoc} */ - public function getApiVersion() + public function getApiVersion(): int { - return PicoDeprecated::API_VERSION_3; + return PicoDeprecated::API_VERSION_4; } } diff --git a/plugins/PicoPluginApi2CompatPlugin.php b/plugins/PicoPluginApi2CompatPlugin.php deleted file mode 100644 index a9ebbee..0000000 --- a/plugins/PicoPluginApi2CompatPlugin.php +++ /dev/null @@ -1,131 +0,0 @@ - - * - * This file was created by splitting up an original file into multiple files, - * which in turn was previously part of the project's main repository. The - * version control history of these files apply accordingly, available from - * the following original locations: - * - * - * - * - * SPDX-License-Identifier: MIT - * License-Filename: LICENSE - */ - -/** - * Maintains backward compatibility with plugins using API version 2, written - * for Pico 2.0 - * - * @author Daniel Rudolf - * @link http://picocms.org - * @license http://opensource.org/licenses/MIT The MIT License - * @version 2.1 - */ -class PicoPluginApi2CompatPlugin extends AbstractPicoPluginApiCompatPlugin -{ - /** - * This plugin extends {@see PicoThemeApi2CompatPlugin} - * - * @var string[] - */ - protected $dependsOn = array('PicoThemeApi2CompatPlugin'); - - /** - * Map of core events matching event signatures of older API versions - * - * @see AbstractPicoPluginApiCompatPlugin::handleEvent() - * - * @var array - */ - protected $eventAliases = array( - 'onPluginsLoaded' => array('onPluginsLoaded'), - 'onPluginManuallyLoaded' => array('onPluginManuallyLoaded'), - 'onRequestUrl' => array('onRequestUrl'), - 'onRequestFile' => array('onRequestFile'), - 'onContentLoading' => array('onContentLoading'), - 'on404ContentLoading' => array('on404ContentLoading'), - 'on404ContentLoaded' => array('on404ContentLoaded'), - 'onContentLoaded' => array('onContentLoaded'), - 'onMetaParsing' => array('onMetaParsing'), - 'onMetaParsed' => array('onMetaParsed'), - 'onContentParsing' => array('onContentParsing'), - 'onContentPrepared' => array('onContentPrepared'), - 'onContentParsed' => array('onContentParsed'), - 'onPagesLoading' => array('onPagesLoading'), - 'onSinglePageLoading' => array('onSinglePageLoading'), - 'onSinglePageContent' => array('onSinglePageContent'), - 'onSinglePageLoaded' => array('onSinglePageLoaded'), - 'onPagesDiscovered' => array('onPagesDiscovered'), - 'onPagesLoaded' => array('onPagesLoaded'), - 'onCurrentPageDiscovered' => array('onCurrentPageDiscovered'), - 'onPageTreeBuilt' => array('onPageTreeBuilt'), - 'onPageRendering' => array('onPageRendering'), - 'onPageRendered' => array('onPageRendered'), - 'onMetaHeaders' => array('onMetaHeaders'), - 'onYamlParserRegistered' => array('onYamlParserRegistered'), - 'onParsedownRegistered' => array('onParsedownRegistered'), - 'onTwigRegistered' => array('onTwigRegistered') - ); - - /** - * Pico's config array - * - * @see Pico::$config - * @see PicoPluginApi2CompatPlugin::onConfigLoaded() - * - * @var array|null - */ - protected $config; - - /** - * Sets PicoPluginApi1CompatPlugin::$config and handles the theme_url - * config param - * - * @see PicoPluginApi2CompatPlugin::$config - * - * @param array $config - */ - public function onConfigLoaded(array &$config) - { - $this->config = &$config; - - if (!empty($config['theme_url'])) { - $config['themes_url'] = $this->getPico()->getAbsoluteUrl($config['theme_url']); - $config['theme_url'] = &$config['themes_url']; - } - } - - /** - * Triggers the onConfigLoaded event - * - * @param string $theme name of current theme - * @param int $themeApiVersion API version of the theme - * @param array &$themeConfig config array of the theme - */ - public function onThemeLoaded($theme, $themeApiVersion, array &$themeConfig) - { - $this->triggerEvent('onConfigLoaded', array(&$this->config)); - } - - /** - * {@inheritDoc} - */ - public function getApiVersion() - { - return PicoDeprecated::API_VERSION_3; - } - - /** - * {@inheritDoc} - */ - public function getApiVersionSupport() - { - return PicoDeprecated::API_VERSION_2; - } -} diff --git a/plugins/PicoPluginApi0CompatPlugin.php b/plugins/PluginApi0Plugin.php similarity index 69% rename from plugins/PicoPluginApi0CompatPlugin.php rename to plugins/PluginApi0Plugin.php index d459524..9622795 100644 --- a/plugins/PicoPluginApi0CompatPlugin.php +++ b/plugins/PluginApi0Plugin.php @@ -4,7 +4,7 @@ * in the version control history of the file, available from the following * original location: * - * + * * * This file was created by splitting up an original file into multiple files, * which in turn was previously part of the project's main repository. The @@ -18,49 +18,58 @@ * License-Filename: LICENSE */ +declare(strict_types=1); + +namespace picocms\PicoDeprecated\Plugin; + +use picocms\PicoDeprecated\AbstractPluginApiPlugin; +use Pico; +use PicoDeprecated; +use ReflectionClass; +use Twig\Environment as TwigEnvironment; + /** * Maintains backward compatibility with plugins using API version 0, written * for Pico 0.9 and earlier * * @author Daniel Rudolf - * @link http://picocms.org - * @license http://opensource.org/licenses/MIT The MIT License - * @version 2.1 + * @link https://picocms.org + * @license https://opensource.org/licenses/MIT The MIT License + * @version 3.0 */ -class PicoPluginApi0CompatPlugin extends AbstractPicoPluginApiCompatPlugin +class PluginApi0Plugin extends AbstractPluginApiPlugin { /** - * This plugin extends {@see PicoPluginApi1CompatPlugin} and - * {@see PicoThemeApi0CompatPlugin} + * This plugin extends {@see PluginApi1Plugin} and {@see ThemeApi0Plugin} * * @var string[] */ - protected $dependsOn = array('PicoPluginApi1CompatPlugin', 'PicoThemeApi0CompatPlugin'); + protected $dependsOn = [ PluginApi1Plugin::class, ThemeApi0Plugin::class ]; /** * Map of core events matching event signatures of older API versions * - * @see AbstractPicoPluginApiCompatPlugin::handleEvent() + * @see AbstractPluginApiPlugin::handleEvent() * * @var array */ - protected $eventAliases = array( - 'onConfigLoaded' => array('config_loaded'), - 'onRequestUrl' => array('request_url'), - 'onContentLoading' => array('before_load_content'), - 'on404ContentLoading' => array('before_404_load_content'), - 'onMetaParsed' => array('file_meta'), - 'onContentParsing' => array('before_parse_content'), - 'onContentParsed' => array('after_parse_content', 'content_parsed'), - 'onTwigRegistration' => array('before_twig_register'), - 'onPageRendered' => array('after_render') - ); + protected $eventAliases = [ + 'onConfigLoaded' => [ 'config_loaded' ], + 'onRequestUrl' => [ 'request_url' ], + 'onContentLoading' => [ 'before_load_content' ], + 'on404ContentLoading' => [ 'before_404_load_content' ], + 'onMetaParsed' => [ 'file_meta' ], + 'onContentParsing' => [ 'before_parse_content' ], + 'onContentParsed' => [ 'after_parse_content', 'content_parsed' ], + 'onTwigRegistration' => [ 'before_twig_register' ], + 'onPageRendered' => [ 'after_render' ], + ]; /** * Pico's request file * * @see Pico::$requestFile - * @see PicoPluginApi0CompatPlugin::onRequestFile() + * @see PluginApi0Plugin::onRequestFile() * * @var string|null */ @@ -71,7 +80,7 @@ class PicoPluginApi0CompatPlugin extends AbstractPicoPluginApiCompatPlugin * * @param object[] $plugins loaded plugin instances */ - public function onPluginsLoaded(array &$plugins) + public function onPluginsLoaded(array &$plugins): void { $this->triggerEvent('plugins_loaded'); } @@ -86,7 +95,7 @@ public function onPluginsLoaded(array &$plugins) * * @param array &$config array of config variables */ - public function onConfigLoaded(array &$config) + public function onConfigLoaded(array &$config): void { $this->defineConfigConstants($config); @@ -105,7 +114,7 @@ public function onConfigLoaded(array &$config) * * @param array &$config array of config variables */ - protected function defineConfigConstants(array &$config) + protected function defineConfigConstants(array &$config): void { if (!defined('ROOT_DIR')) { define('ROOT_DIR', $this->getPico()->getRootDir()); @@ -114,7 +123,7 @@ protected function defineConfigConstants(array &$config) define('CONFIG_DIR', $this->getPico()->getConfigDir()); } if (!defined('LIB_DIR')) { - $picoReflector = new ReflectionClass('Pico'); + $picoReflector = new ReflectionClass(Pico::class); define('LIB_DIR', dirname($picoReflector->getFileName()) . '/'); } if (!defined('PLUGINS_DIR')) { @@ -136,13 +145,13 @@ protected function defineConfigConstants(array &$config) } /** - * Sets PicoPluginApi1CompatPlugin::$requestFile + * Sets PluginApi0Plugin::$requestFile * - * @see PicoPluginApi0CompatPlugin::$requestFile + * @see PluginApi0Plugin::$requestFile * * @param string &$file absolute path to the content file to serve */ - public function onRequestFile(&$file) + public function onRequestFile(string &$file): void { $this->requestFile = &$file; } @@ -152,9 +161,9 @@ public function onRequestFile(&$file) * * @param string &$rawContent raw file contents */ - public function on404ContentLoaded(&$rawContent) + public function on404ContentLoaded(string &$rawContent): void { - $this->triggerEvent('after_404_load_content', array(&$this->requestFile, &$rawContent)); + $this->triggerEvent('after_404_load_content', [ &$this->requestFile, &$rawContent ]); } /** @@ -162,9 +171,9 @@ public function on404ContentLoaded(&$rawContent) * * @param string &$rawContent raw file contents */ - public function onContentLoaded(&$rawContent) + public function onContentLoaded(string &$rawContent): void { - $this->triggerEvent('after_load_content', array(&$this->requestFile, &$rawContent)); + $this->triggerEvent('after_load_content', [ &$this->requestFile, &$rawContent ]); } /** @@ -173,9 +182,9 @@ public function onContentLoaded(&$rawContent) * @param string &$rawContent raw file contents * @param string[] &$headers list of known meta header fields */ - public function onMetaParsing(&$rawContent, array &$headers) + public function onMetaParsing(string &$rawContent, array &$headers): void { - $this->triggerEvent('before_read_file_meta', array(&$headers)); + $this->triggerEvent('before_read_file_meta', [ &$headers ]); } /** @@ -183,9 +192,9 @@ public function onMetaParsing(&$rawContent, array &$headers) * * @param array &$pageData data of the loaded page */ - public function onSinglePageLoaded(array &$pageData) + public function onSinglePageLoaded(array &$pageData): void { - $this->triggerEvent('get_page_data', array(&$pageData, $pageData['meta'])); + $this->triggerEvent('get_page_data', [ &$pageData, $pageData['meta'] ]); } /** @@ -207,26 +216,26 @@ public function onPagesLoaded( array &$currentPage = null, array &$previousPage = null, array &$nextPage = null - ) { + ): void { // remove keys of pages array - $plainPages = array(); + $plainPages = []; foreach ($pages as &$plainPageData) { $plainPages[] = &$plainPageData; } // trigger event - $this->triggerEvent('get_pages', array(&$plainPages, &$currentPage, &$previousPage, &$nextPage)); + $this->triggerEvent('get_pages', [ &$plainPages, &$currentPage, &$previousPage, &$nextPage ]); // re-index pages array $baseUrl = $this->getPico()->getBaseUrl(); $baseUrlLength = strlen($baseUrl); $urlRewritingEnabled = $this->getPico()->isUrlRewritingEnabled(); - $pages = array(); + $pages = []; foreach ($plainPages as &$pageData) { if (!isset($pageData['id'])) { - if (substr($pageData['url'], 0, $baseUrlLength) === $baseUrl) { - if ($urlRewritingEnabled && (substr($pageData['url'], $baseUrlLength, 1) === '?')) { + if (substr_compare($pageData['url'], $baseUrl, 0, $baseUrlLength) === 0) { + if ($urlRewritingEnabled && (substr_compare($pageData['url'], '?', $baseUrlLength, 1) === 0)) { $pageData['id'] = substr($pageData['url'], $baseUrlLength + 1); } else { $pageData['id'] = substr($pageData['url'], $baseUrlLength); @@ -253,18 +262,18 @@ public function onPagesLoaded( * Please note that the `before_render` event gets `$templateName` passed * without its file extension. The file extension is re-added later. * - * @param Twig_Environment &$twig Twig instance - * @param string &$templateName file name of the template - * @param array &$twigVariables template variables + * @param TwigEnvironment &$twig Twig instance + * @param array &$twigVariables template variables + * @param string &$templateName file name of the template */ - public function onPageRendering(Twig_Environment &$twig, array &$twigVariables, &$templateName) + public function onPageRendering(TwigEnvironment &$twig, array &$twigVariables, string &$templateName): void { - $templateNameInfo = pathinfo($templateName) + array('extension' => ''); + $templateNameInfo = pathinfo($templateName) + [ 'extension' => '' ]; // the template name hasn't had a file extension in API v0 $templateName = $templateNameInfo['filename']; - $this->triggerEvent('before_render', array(&$twigVariables, &$twig, &$templateName)); + $this->triggerEvent('before_render', [ &$twigVariables, &$twig, &$templateName ]); // recover original file extension // we assume that all templates of a theme use the same file extension @@ -274,7 +283,7 @@ public function onPageRendering(Twig_Environment &$twig, array &$twigVariables, /** * {@inheritDoc} */ - public function handleCustomEvent($eventName, array $params = array()) + public function handleCustomEvent(string $eventName, array $params = []): void { // never trigger custom events } @@ -282,7 +291,7 @@ public function handleCustomEvent($eventName, array $params = array()) /** * {@inheritDoc} */ - public function triggerEvent($eventName, array $params = array()) + public function triggerEvent(string $eventName, array $params = []): void { // we don't support compat plugins using API v0, so no need to take care of compat plugins here // API v0 events are also triggered on plugins using API v1 (but not later) @@ -291,7 +300,7 @@ public function triggerEvent($eventName, array $params = array()) foreach ($plugins as $plugin) { if (method_exists($plugin, $eventName)) { - call_user_func_array(array($plugin, $eventName), $params); + call_user_func_array([ $plugin, $eventName ], $params); } } } @@ -299,7 +308,7 @@ public function triggerEvent($eventName, array $params = array()) /** * {@inheritDoc} */ - public function getApiVersion() + public function getApiVersion(): int { return PicoDeprecated::API_VERSION_1; } @@ -307,7 +316,7 @@ public function getApiVersion() /** * {@inheritDoc} */ - public function getApiVersionSupport() + public function getApiVersionSupport(): int { return PicoDeprecated::API_VERSION_0; } diff --git a/plugins/PicoPluginApi1CompatPlugin.php b/plugins/PluginApi1Plugin.php similarity index 66% rename from plugins/PicoPluginApi1CompatPlugin.php rename to plugins/PluginApi1Plugin.php index ea886df..0bdab13 100644 --- a/plugins/PicoPluginApi1CompatPlugin.php +++ b/plugins/PluginApi1Plugin.php @@ -4,7 +4,7 @@ * in the version control history of the file, available from the following * original location: * - * + * * * This file was created by splitting up an original file into multiple files, * which in turn was previously part of the project's main repository. The @@ -18,50 +18,58 @@ * License-Filename: LICENSE */ +declare(strict_types=1); + +namespace picocms\PicoDeprecated\Plugin; + +use picocms\PicoDeprecated\AbstractPluginApiPlugin; +use PicoDeprecated; +use RuntimeException; +use Twig\Environment as TwigEnvironment; + /** * Maintains backward compatibility with plugins using API version 1, written * for Pico 1.0 * * @author Daniel Rudolf - * @link http://picocms.org - * @license http://opensource.org/licenses/MIT The MIT License - * @version 2.1 + * @link https://picocms.org + * @license https://opensource.org/licenses/MIT The MIT License + * @version 3.0 */ -class PicoPluginApi1CompatPlugin extends AbstractPicoPluginApiCompatPlugin +class PluginApi1Plugin extends AbstractPluginApiPlugin { /** - * This plugin extends {@see PicoPluginApi2CompatPlugin} and - * {@see PicoThemeApi1CompatPlugin} + * This plugin extends {@see PluginApi2Plugin} and {@see ThemeApi1Plugin} * * @var string[] */ - protected $dependsOn = array('PicoPluginApi2CompatPlugin', 'PicoThemeApi1CompatPlugin'); + protected $dependsOn = [ PluginApi2Plugin::class, ThemeApi1Plugin::class ]; /** * Map of core events matching event signatures of older API versions * - * @see AbstractPicoPluginApiCompatPlugin::handleEvent() + * @see AbstractPluginApiPlugin::handleEvent() * * @var array */ - protected $eventAliases = array( - 'onConfigLoaded' => array('onConfigLoaded'), - 'onRequestUrl' => array('onRequestUrl'), - 'onRequestFile' => array('onRequestFile'), - 'on404ContentLoaded' => array('on404ContentLoaded'), - 'onContentLoaded' => array('onContentLoaded'), - 'onContentPrepared' => array('onContentPrepared'), - 'onContentParsed' => array('onContentParsed'), - 'onPagesLoading' => array('onPagesLoading'), - 'onSinglePageLoaded' => array('onSinglePageLoaded'), - 'onPageRendered' => array('onPageRendered') - ); + protected $eventAliases = [ + 'onConfigLoaded' => [ 'onConfigLoaded' ], + 'onRequestUrl' => [ 'onRequestUrl' ], + 'onRequestFile' => [ 'onRequestFile' ], + 'on404ContentLoaded' => [ 'on404ContentLoaded' ], + 'onContentLoaded' => [ 'onContentLoaded' ], + 'onContentPrepared' => [ 'onContentPrepared' ], + 'onContentParsed' => [ 'onContentParsed' ], + 'onPagesLoading' => [ 'onPagesLoading' ], + 'onSinglePageLoaded' => [ 'onSinglePageLoaded' ], + 'onPageRendered' => [ 'onPageRendered' ], + ]; /** * Pico's request file * * @see Pico::$requestFile - * @see PicoPluginApi1CompatPlugin::onRequestFile() + * @see PluginApi1Plugin::onRequestFile() * * @var string|null */ @@ -71,7 +79,7 @@ class PicoPluginApi1CompatPlugin extends AbstractPicoPluginApiCompatPlugin * Pico's raw contents * * @see Pico::$rawContent - * @see PicoPluginApi1CompatPlugin::onContentLoaded() + * @see PluginApi1Plugin::onContentLoaded() * * @var string|null */ @@ -81,7 +89,7 @@ class PicoPluginApi1CompatPlugin extends AbstractPicoPluginApiCompatPlugin * Pico's meta headers array * * @see Pico::$metaHeaders - * @see PicoPluginApi1CompatPlugin::onMetaHeaders() + * @see PluginApi1Plugin::onMetaHeaders() * * @var array|null */ @@ -91,7 +99,7 @@ class PicoPluginApi1CompatPlugin extends AbstractPicoPluginApiCompatPlugin * Pico's pages array * * @see Pico::$pages - * @see PicoPluginApi1CompatPlugin::onPagesLoaded() + * @see PluginApi1Plugin::onPagesLoaded() * * @var array[]|null */ @@ -101,9 +109,9 @@ class PicoPluginApi1CompatPlugin extends AbstractPicoPluginApiCompatPlugin * Pico's Twig instance * * @see Pico::$twig - * @see PicoPluginApi1CompatPlugin::onTwigRegistered() + * @see PluginApi1Plugin::onTwigRegistered() * - * @var Twig_Environment|null + * @var TwigEnvironment|null */ protected $twig; @@ -118,11 +126,11 @@ class PicoPluginApi1CompatPlugin extends AbstractPicoPluginApiCompatPlugin * * @param object[] $plugins loaded plugin instances */ - public function onPluginsLoaded(array $plugins) + public function onPluginsLoaded(array $plugins): void { $originalPlugins = $plugins; - $this->triggerEvent('onPluginsLoaded', array(&$plugins)); + $this->triggerEvent('onPluginsLoaded', [ &$plugins ]); foreach ($plugins as $pluginName => $plugin) { if (!isset($originalPlugins[$pluginName])) { @@ -147,13 +155,13 @@ public function onPluginsLoaded(array $plugins) } /** - * Sets PicoPluginApi1CompatPlugin::$requestFile + * Sets PluginApi1Plugin::$requestFile * - * @see PicoPluginApi1CompatPlugin::$requestFile + * @see PluginApi1Plugin::$requestFile * * @param string &$file absolute path to the content file to serve */ - public function onRequestFile(&$file) + public function onRequestFile(string &$file): void { $this->requestFile = &$file; } @@ -161,19 +169,19 @@ public function onRequestFile(&$file) /** * Triggers the onContentLoading event */ - public function onContentLoading() + public function onContentLoading(): void { - $this->triggerEvent('onContentLoading', array(&$this->requestFile)); + $this->triggerEvent('onContentLoading', [ &$this->requestFile ]); } /** - * Sets PicoPluginApi1CompatPlugin::$rawContent + * Sets PluginApi1Plugin::$rawContent * - * @see PicoPluginApi1CompatPlugin::$rawContent + * @see PluginApi1Plugin::$rawContent * * @param string &$rawContent raw file contents */ - public function onContentLoaded(&$rawContent) + public function onContentLoaded(string &$rawContent): void { $this->rawContent = &$rawContent; } @@ -181,20 +189,20 @@ public function onContentLoaded(&$rawContent) /** * Triggers the on404ContentLoading event */ - public function on404ContentLoading() + public function on404ContentLoading(): void { - $this->triggerEvent('on404ContentLoading', array(&$this->requestFile)); + $this->triggerEvent('on404ContentLoading', [ &$this->requestFile ]); } /** * Triggers the onMetaParsing event * - * @see PicoPluginApi1CompatPlugin::onMetaHeaders() + * @see PluginApi1Plugin::onMetaHeaders() */ - public function onMetaParsing() + public function onMetaParsing(): void { $headersFlipped = $this->getFlippedMetaHeaders(); - $this->triggerEvent('onMetaParsing', array(&$this->rawContent, &$headersFlipped)); + $this->triggerEvent('onMetaParsing', [ &$this->rawContent, &$headersFlipped ]); $this->updateFlippedMetaHeaders($headersFlipped); } @@ -203,28 +211,28 @@ public function onMetaParsing() * * @param string[] &$meta parsed meta data */ - public function onMetaParsed(array &$meta) + public function onMetaParsed(array &$meta): void { - $this->triggerEvent('onMetaParsed', array(&$meta)); + $this->triggerEvent('onMetaParsed', [ &$meta ]); $this->triggerEvent('onParsedownRegistration'); } /** * Triggers the onContentParsing event */ - public function onContentParsing() + public function onContentParsing(): void { - $this->triggerEvent('onContentParsing', array(&$this->rawContent)); + $this->triggerEvent('onContentParsing', [ &$this->rawContent ]); } /** - * Sets PicoPluginApi1CompatPlugin::$pages + * Sets PluginApi1Plugin::$pages * - * @see PicoPluginApi1CompatPlugin::$pages + * @see PluginApi1Plugin::$pages * * @param array[] &$pages sorted list of all known pages */ - public function onPagesLoaded(array &$pages) + public function onPagesLoaded(array &$pages): void { $this->pages = &$pages; } @@ -240,8 +248,8 @@ public function onCurrentPageDiscovered( array &$currentPage = null, array &$previousPage = null, array &$nextPage = null - ) { - $this->triggerEvent('onPagesLoaded', array(&$this->pages, &$currentPage, &$previousPage, &$nextPage)); + ): void { + $this->triggerEvent('onPagesLoaded', [ &$this->pages, &$currentPage, &$previousPage, &$nextPage ]); $this->triggerEvent('onTwigRegistration'); $this->getPico()->getTwig(); @@ -253,38 +261,38 @@ public function onCurrentPageDiscovered( * @param string &$templateName file name of the template * @param array &$twigVariables template variables */ - public function onPageRendering(&$templateName, array &$twigVariables) + public function onPageRendering(string &$templateName, array &$twigVariables): void { - $this->triggerEvent('onPageRendering', array(&$this->twig, &$twigVariables, &$templateName)); + $this->triggerEvent('onPageRendering', [ &$this->twig, &$twigVariables, &$templateName ]); } /** * Triggers the onMetaHeaders event with flipped meta headers and sets - * PicoPluginApi1CompatPlugin::$metaHeaders + * PluginApi1Plugin::$metaHeaders * - * @see PicoPluginApi1CompatPlugin::$metaHeaders + * @see PluginApi1Plugin::$metaHeaders * * @param string[] &$headers list of known meta header fields; the array * key specifies the YAML key to search for, the array value is later * used to access the found value */ - public function onMetaHeaders(array &$headers) + public function onMetaHeaders(array &$headers): void { $this->metaHeaders = &$headers; $headersFlipped = $this->getFlippedMetaHeaders(); - $this->triggerEvent('onMetaHeaders', array(&$headersFlipped)); + $this->triggerEvent('onMetaHeaders', [ &$headersFlipped ]); $this->updateFlippedMetaHeaders($headersFlipped); } /** - * Sets PicoPluginApi1CompatPlugin::$twig + * Sets PluginApi1Plugin::$twig * - * @see PicoPluginApi1CompatPlugin::$twig + * @see PluginApi1Plugin::$twig * - * @param Twig_Environment &$twig Twig instance + * @param TwigEnvironment &$twig Twig instance */ - public function onTwigRegistered(Twig_Environment &$twig) + public function onTwigRegistered(TwigEnvironment &$twig): void { $this->twig = $twig; } @@ -301,22 +309,22 @@ public function onTwigRegistered(Twig_Environment &$twig) * * @return array flipped meta headers */ - protected function getFlippedMetaHeaders() + protected function getFlippedMetaHeaders(): array { if ($this->metaHeaders === null) { // make sure to trigger the onMetaHeaders event $this->getPico()->getMetaHeaders(); } - return array_flip($this->metaHeaders ?: array()); + return array_flip($this->metaHeaders ?: []); } /** - * Syncs PicoPluginApi1CompatPlugin::$metaHeaders with a flipped headers array + * Syncs PluginApi1Plugin::$metaHeaders with a flipped headers array * * @param array $headersFlipped flipped headers array */ - protected function updateFlippedMetaHeaders(array $headersFlipped) + protected function updateFlippedMetaHeaders(array $headersFlipped): void { foreach ($this->metaHeaders as $name => $key) { if (!isset($headersFlipped[$key])) { @@ -332,7 +340,7 @@ protected function updateFlippedMetaHeaders(array $headersFlipped) /** * {@inheritDoc} */ - public function getApiVersion() + public function getApiVersion(): int { return PicoDeprecated::API_VERSION_2; } @@ -340,7 +348,7 @@ public function getApiVersion() /** * {@inheritDoc} */ - public function getApiVersionSupport() + public function getApiVersionSupport(): int { return PicoDeprecated::API_VERSION_1; } diff --git a/plugins/PluginApi2Plugin.php b/plugins/PluginApi2Plugin.php new file mode 100644 index 0000000..84ba0b7 --- /dev/null +++ b/plugins/PluginApi2Plugin.php @@ -0,0 +1,137 @@ + + * + * This file was created by splitting up an original file into multiple files, + * which in turn was previously part of the project's main repository. The + * version control history of these files apply accordingly, available from + * the following original locations: + * + * + * + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +declare(strict_types=1); + +namespace picocms\PicoDeprecated\Plugin; + +use picocms\PicoDeprecated\AbstractPluginApiPlugin; +use PicoDeprecated; + +/** + * Maintains backward compatibility with plugins using API version 2, written + * for Pico 2.0 + * + * @author Daniel Rudolf + * @link https://picocms.org + * @license https://opensource.org/licenses/MIT The MIT License + * @version 3.0 + */ +class PluginApi2Plugin extends AbstractPluginApiPlugin +{ + /** + * This plugin extends {@see ThemeApi2Plugin} + * + * @var string[] + */ + protected $dependsOn = [ PluginApi3Plugin::class, ThemeApi2Plugin::class ]; + + /** + * Map of core events matching event signatures of older API versions + * + * @see AbstractPluginApiPlugin::handleEvent() + * + * @var array + */ + protected $eventAliases = [ + 'onPluginsLoaded' => [ 'onPluginsLoaded' ], + 'onPluginManuallyLoaded' => [ 'onPluginManuallyLoaded' ], + 'onRequestUrl' => [ 'onRequestUrl' ], + 'onRequestFile' => [ 'onRequestFile' ], + 'onContentLoading' => [ 'onContentLoading' ], + 'on404ContentLoading' => [ 'on404ContentLoading' ], + 'on404ContentLoaded' => [ 'on404ContentLoaded' ], + 'onContentLoaded' => [ 'onContentLoaded' ], + 'onMetaParsing' => [ 'onMetaParsing' ], + 'onMetaParsed' => [ 'onMetaParsed' ], + 'onContentParsing' => [ 'onContentParsing' ], + 'onContentPrepared' => [ 'onContentPrepared' ], + 'onContentParsed' => [ 'onContentParsed' ], + 'onPagesLoading' => [ 'onPagesLoading' ], + 'onSinglePageLoading' => [ 'onSinglePageLoading' ], + 'onSinglePageContent' => [ 'onSinglePageContent' ], + 'onSinglePageLoaded' => [ 'onSinglePageLoaded' ], + 'onPagesDiscovered' => [ 'onPagesDiscovered' ], + 'onPagesLoaded' => [ 'onPagesLoaded' ], + 'onCurrentPageDiscovered' => [ 'onCurrentPageDiscovered' ], + 'onPageTreeBuilt' => [ 'onPageTreeBuilt' ], + 'onPageRendering' => [ 'onPageRendering' ], + 'onPageRendered' => [ 'onPageRendered' ], + 'onMetaHeaders' => [ 'onMetaHeaders' ], + 'onYamlParserRegistered' => [ 'onYamlParserRegistered' ], + 'onParsedownRegistered' => [ 'onParsedownRegistered' ], + 'onTwigRegistered' => [ 'onTwigRegistered' ], + ]; + + /** + * Pico's config array + * + * @see Pico::$config + * @see PluginApi2Plugin::onConfigLoaded() + * + * @var array|null + */ + protected $config; + + /** + * Sets PluginApi2Plugin::$config and handles the theme_url config param + * + * @see PluginApi2Plugin::$config + * + * @param array $config + */ + public function onConfigLoaded(array &$config): void + { + $this->config = &$config; + + if (!empty($config['theme_url'])) { + $config['themes_url'] = $this->getPico()->getAbsoluteUrl($config['theme_url']); + $config['theme_url'] = &$config['themes_url']; + } + } + + /** + * Triggers the onConfigLoaded event + * + * @param string $theme name of current theme + * @param int $themeApiVersion API version of the theme + * @param array &$themeConfig config array of the theme + */ + public function onThemeLoaded(string $theme, int $themeApiVersion, array &$themeConfig): void + { + $this->triggerEvent('onConfigLoaded', [ &$this->config ]); + } + + /** + * {@inheritDoc} + */ + public function getApiVersion(): int + { + return PicoDeprecated::API_VERSION_3; + } + + /** + * {@inheritDoc} + */ + public function getApiVersionSupport(): int + { + return PicoDeprecated::API_VERSION_2; + } +} diff --git a/plugins/PluginApi3Plugin.php b/plugins/PluginApi3Plugin.php new file mode 100644 index 0000000..df5a3e5 --- /dev/null +++ b/plugins/PluginApi3Plugin.php @@ -0,0 +1,86 @@ + + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +declare(strict_types=1); + +namespace picocms\PicoDeprecated\Plugin; + +use picocms\PicoDeprecated\AbstractPluginApiPlugin; +use PicoDeprecated; + +/** + * Maintains backward compatibility with plugins using API version 3, written + * for Pico 2.1 + * + * @author Daniel Rudolf + * @link https://picocms.org + * @license https://opensource.org/licenses/MIT The MIT License + * @version 3.0 + */ +class PluginApi3Plugin extends AbstractPluginApiPlugin +{ + /** + * Map of core events matching event signatures of older API versions + * + * @see AbstractPluginApiPlugin::handleEvent() + * + * @var array + */ + protected $eventAliases = [ + 'onPluginsLoaded' => [ 'onPluginsLoaded' ], + 'onPluginManuallyLoaded' => [ 'onPluginManuallyLoaded' ], + 'onConfigLoaded' => [ 'onConfigLoaded' ], + 'onThemeLoading' => [ 'onThemeLoading' ], + 'onThemeLoaded' => [ 'onThemeLoaded' ], + 'onRequestUrl' => [ 'onRequestUrl' ], + 'onRequestFile' => [ 'onRequestFile' ], + 'onContentLoading' => [ 'onContentLoading' ], + 'on404ContentLoading' => [ 'on404ContentLoading' ], + 'on404ContentLoaded' => [ 'on404ContentLoaded' ], + 'onContentLoaded' => [ 'onContentLoaded' ], + 'onMetaParsing' => [ 'onMetaParsing' ], + 'onMetaParsed' => [ 'onMetaParsed' ], + 'onContentParsing' => [ 'onContentParsing' ], + 'onContentPrepared' => [ 'onContentPrepared' ], + 'onContentParsed' => [ 'onContentParsed' ], + 'onPagesLoading' => [ 'onPagesLoading' ], + 'onSinglePageLoading' => [ 'onSinglePageLoading' ], + 'onSinglePageContent' => [ 'onSinglePageContent' ], + 'onSinglePageLoaded' => [ 'onSinglePageLoaded' ], + 'onPagesDiscovered' => [ 'onPagesDiscovered' ], + 'onPagesLoaded' => [ 'onPagesLoaded' ], + 'onCurrentPageDiscovered' => [ 'onCurrentPageDiscovered' ], + 'onPageTreeBuilt' => [ 'onPageTreeBuilt' ], + 'onPageRendering' => [ 'onPageRendering' ], + 'onPageRendered' => [ 'onPageRendered' ], + 'onMetaHeaders' => [ 'onMetaHeaders' ], + 'onYamlParserRegistered' => [ 'onYamlParserRegistered' ], + 'onParsedownRegistered' => [ 'onParsedownRegistered' ], + 'onTwigRegistered' => [ 'onTwigRegistered' ], + ]; + + /** + * {@inheritDoc} + */ + public function getApiVersion(): int + { + return PicoDeprecated::API_VERSION_4; + } + + /** + * {@inheritDoc} + */ + public function getApiVersionSupport(): int + { + return PicoDeprecated::API_VERSION_3; + } +} diff --git a/plugins/PicoThemeApi0CompatPlugin.php b/plugins/ThemeApi0Plugin.php similarity index 67% rename from plugins/PicoThemeApi0CompatPlugin.php rename to plugins/ThemeApi0Plugin.php index 9ed6a64..b378c17 100644 --- a/plugins/PicoThemeApi0CompatPlugin.php +++ b/plugins/ThemeApi0Plugin.php @@ -4,7 +4,7 @@ * in the version control history of the file, available from the following * original location: * - * + * * * This file was created by splitting up an original file into multiple files, * which in turn was previously part of the project's main repository. The @@ -18,34 +18,41 @@ * License-Filename: LICENSE */ +declare(strict_types=1); + +namespace picocms\PicoDeprecated\Plugin; + +use picocms\PicoDeprecated\AbstractPlugin; +use PicoDeprecated; + /** * Maintains backward compatibility with themes using API version 0, written * for Pico 0.9 and earlier * * Since there were no theme-related changes between Pico 0.9 and Pico 1.0, * this compat plugin doesn't hold any code itself, it just depends on - * {@see PicoThemeApi1CompatPlugin}. Since themes didn't support API versioning - * until Pico 2.1 (i.e. API version 3), all older themes will appear to use API + * {@see ThemeApi1Plugin}. Since themes didn't support API versioning until + * Pico 2.1 (i.e. API version 3), all older themes will appear to use API * version 0. * * @author Daniel Rudolf - * @link http://picocms.org - * @license http://opensource.org/licenses/MIT The MIT License - * @version 2.1 + * @link https://picocms.org + * @license https://opensource.org/licenses/MIT The MIT License + * @version 3.0 */ -class PicoThemeApi0CompatPlugin extends AbstractPicoCompatPlugin +class ThemeApi0Plugin extends AbstractPlugin { /** - * This plugin extends {@see PicoThemeApi1CompatPlugin} + * This plugin extends {@see ThemeApi1Plugin} * * @var string[] */ - protected $dependsOn = array('PicoThemeApi1CompatPlugin'); + protected $dependsOn = [ ThemeApi1Plugin::class ]; /** * {@inheritDoc} */ - public function getApiVersion() + public function getApiVersion(): int { return PicoDeprecated::API_VERSION_3; } diff --git a/plugins/PicoThemeApi1CompatPlugin.php b/plugins/ThemeApi1Plugin.php similarity index 78% rename from plugins/PicoThemeApi1CompatPlugin.php rename to plugins/ThemeApi1Plugin.php index f4b276b..ee17208 100644 --- a/plugins/PicoThemeApi1CompatPlugin.php +++ b/plugins/ThemeApi1Plugin.php @@ -4,7 +4,7 @@ * in the version control history of the file, available from the following * original location: * - * + * * * This file was created by splitting up an original file into multiple files, * which in turn was previously part of the project's main repository. The @@ -18,32 +18,40 @@ * License-Filename: LICENSE */ +declare(strict_types=1); + +namespace picocms\PicoDeprecated\Plugin; + +use picocms\PicoDeprecated\AbstractPlugin; +use PicoDeprecated; +use Twig\Error\LoaderError as TwigLoaderError; + /** * Maintains backward compatibility with themes using API version 1, written * for Pico 1.0 * * @author Daniel Rudolf - * @link http://picocms.org - * @license http://opensource.org/licenses/MIT The MIT License - * @version 2.1 + * @link https://picocms.org + * @license https://opensource.org/licenses/MIT The MIT License + * @version 3.0 */ -class PicoThemeApi1CompatPlugin extends AbstractPicoCompatPlugin +class ThemeApi1Plugin extends AbstractPlugin { /** - * This plugin extends {@see PicoThemeApi2CompatPlugin} + * This plugin extends {@see ThemeApi2Plugin} * * @var string[] */ - protected $dependsOn = array('PicoThemeApi2CompatPlugin'); + protected $dependsOn = [ ThemeApi2Plugin::class ]; /** * Lowers the page's meta headers * - * @see PicoThemeApi1CompatPlugin::lowerFileMeta() + * @see ThemeApi1Plugin::lowerFileMeta() * * @param string[] &$meta parsed meta data */ - public function onMetaParsed(array &$meta) + public function onMetaParsed(array &$meta): void { $this->lowerFileMeta($meta); } @@ -51,11 +59,11 @@ public function onMetaParsed(array &$meta) /** * Lowers the page's meta headers * - * @see PicoThemeApi1CompatPlugin::lowerFileMeta() + * @see ThemeApi1Plugin::lowerFileMeta() * * @param array &$pageData data of the loaded page */ - public function onSinglePageLoaded(array &$pageData) + public function onSinglePageLoaded(array &$pageData): void { // don't lower the file meta of the requested page, // it was already lowered during the onMetaParsed event @@ -67,13 +75,13 @@ public function onSinglePageLoaded(array &$pageData) } /** - * Handles .html Twig templates and re-introcudes the Twig variables + * Handles .html Twig templates and re-introduces the Twig variables * rewrite_url and is_front_page * * @param string &$templateName file name of the template * @param array &$twigVariables template variables */ - public function onPageRendering(&$templateName, array &$twigVariables) + public function onPageRendering(string &$templateName, array &$twigVariables): void { if (!isset($twigVariables['rewrite_url'])) { $twigVariables['rewrite_url'] = $this->getPico()->isUrlRewritingEnabled(); @@ -88,19 +96,18 @@ public function onPageRendering(&$templateName, array &$twigVariables) // API v2 requires themes to use .twig as file extension // try to load the template and if this fails, try .html instead (as of API v1) - $templateNameInfo = pathinfo($templateName) + array('extension' => ''); + $templateNameInfo = pathinfo($templateName) + [ 'extension' => '' ]; $twig = $this->getPico()->getTwig(); try { - $twig->loadTemplate($templateName); - } catch (Twig_Error_Loader $e) { + $twig->load($templateName); + } catch (TwigLoaderError $e) { if ($templateNameInfo['extension'] === 'twig') { try { - $twig->loadTemplate($templateNameInfo['filename'] . '.html'); + $twig->load($templateNameInfo['filename'] . '.html'); $templateName = $templateNameInfo['filename'] . '.html'; - $templateNameInfo['extension'] = 'html'; - } catch (Twig_Error_Loader $e) { + } catch (TwigLoaderError $e) { // template doesn't exist, Twig will very likely fail later } } @@ -115,12 +122,12 @@ public function onPageRendering(&$templateName, array &$twigVariables) * * @param array &$meta meta data */ - protected function lowerFileMeta(array &$meta) + protected function lowerFileMeta(array &$meta): void { $metaHeaders = $this->getPico()->getMetaHeaders(); // get unregistered meta - $unregisteredMeta = array(); + $unregisteredMeta = []; foreach ($meta as $key => $value) { if (!in_array($key, $metaHeaders)) { $unregisteredMeta[$key] = &$meta[$key]; @@ -147,7 +154,7 @@ protected function lowerFileMeta(array &$meta) /** * {@inheritDoc} */ - public function getApiVersion() + public function getApiVersion(): int { return PicoDeprecated::API_VERSION_3; } diff --git a/plugins/PicoThemeApi2CompatPlugin.php b/plugins/ThemeApi2Plugin.php similarity index 71% rename from plugins/PicoThemeApi2CompatPlugin.php rename to plugins/ThemeApi2Plugin.php index 646925b..73de6c8 100644 --- a/plugins/PicoThemeApi2CompatPlugin.php +++ b/plugins/ThemeApi2Plugin.php @@ -4,7 +4,7 @@ * in the version control history of the file, available from the following * original location: * - * + * * * This file was created by splitting up an original file into multiple files, * which in turn was previously part of the project's main repository. The @@ -18,17 +18,36 @@ * License-Filename: LICENSE */ +declare(strict_types=1); + +namespace picocms\PicoDeprecated\Plugin; + +use picocms\PicoDeprecated\AbstractPlugin; +use PicoDeprecated; +use ReflectionObject; +use Twig\Environment as TwigEnvironment; +use Twig\Error\LoaderError as TwigLoaderError; +use Twig\Extension\EscaperExtension as TwigEscaperExtension; +use Twig\Loader\LoaderInterface as TwigLoaderInterface; + /** * Maintains backward compatibility with themes using API version 2, written * for Pico 2.0 * * @author Daniel Rudolf - * @link http://picocms.org - * @license http://opensource.org/licenses/MIT The MIT License - * @version 2.1 + * @link https://picocms.org + * @license https://opensource.org/licenses/MIT The MIT License + * @version 3.0 */ -class PicoThemeApi2CompatPlugin extends AbstractPicoCompatPlugin +class ThemeApi2Plugin extends AbstractPlugin { + /** + * This plugin extends {@see ThemeApi3Plugin} + * + * @var string[] + */ + protected $dependsOn = [ ThemeApi3Plugin::class ]; + /** * Manually configured Twig escape strategy * @@ -41,16 +60,16 @@ class PicoThemeApi2CompatPlugin extends AbstractPicoCompatPlugin * * @var string[] */ - protected $pluginPaths = array(); + protected $pluginPaths = []; /** - * Sets PicoThemeApi2CompatPlugin::$twigEscapeStrategy + * Sets ThemeApi2Plugin::$twigEscapeStrategy * - * @see PicoThemeApi2CompatPlugin::$twigEscapeStrategy + * @see ThemeApi2Plugin::$twigEscapeStrategy * * @param array &$config array of config variables */ - public function onConfigLoaded(array &$config) + public function onConfigLoaded(array &$config): void { if (isset($config['twig_config']['autoescape'])) { $this->twigEscapeStrategy = $config['twig_config']['autoescape']; @@ -63,7 +82,7 @@ public function onConfigLoaded(array &$config) * @param string &$templateName file name of the template * @param array &$twigVariables template variables */ - public function onPageRendering(&$templateName, array &$twigVariables) + public function onPageRendering(string &$templateName, array &$twigVariables): void { $twigVariables['prev_page'] = &$twigVariables['previous_page']; $twigVariables['base_dir'] = rtrim($this->getPico()->getRootDir(), '/'); @@ -71,19 +90,19 @@ public function onPageRendering(&$templateName, array &$twigVariables) } /** - * Registers PicoPluginApi2CompatPlugin::twigEscapeStrategy() as Twig's - * default escape strategy + * Registers ThemeApi2Plugin::twigEscapeStrategy() as Twig's default + * escape strategy * - * @see PicoPluginApi2CompatPlugin::twigEscapeStrategy() + * @see ThemeApi2Plugin::twigEscapeStrategy() * - * @param Twig_Environment &$twig Twig instance + * @param TwigEnvironment &$twig Twig instance */ - public function onTwigRegistered(Twig_Environment &$twig) + public function onTwigRegistered(TwigEnvironment &$twig): void { - if ($twig->hasExtension('Twig_Extension_Escaper')) { - /** @var Twig_Extension_Escaper $escaperExtension */ - $escaperExtension = $twig->getExtension('Twig_Extension_Escaper'); - $escaperExtension->setDefaultStrategy(array($this, 'twigEscapeStrategy')); + if ($twig->hasExtension(TwigEscaperExtension::class)) { + /** @var TwigEscaperExtension $escaperExtension */ + $escaperExtension = $twig->getExtension(TwigEscaperExtension::class); + $escaperExtension->setDefaultStrategy([ $this, 'twigEscapeStrategy' ]); } } @@ -101,7 +120,7 @@ public function onTwigRegistered(Twig_Environment &$twig) * * @return string|false escape strategy for this template */ - public function twigEscapeStrategy($templateName) + public function twigEscapeStrategy(string $templateName) { $twigConfig = $this->getPico()->getConfig('twig_config'); $escapeStrategy = $twigConfig['autoescape']; @@ -118,24 +137,18 @@ public function twigEscapeStrategy($templateName) return false; } - /** @var Twig_SourceContextLoaderInterface $twigLoader */ + /** @var TwigLoaderInterface $twigLoader */ $twigLoader = $this->getPico()->getTwig()->getLoader(); - if (!$twigLoader instanceof Twig_SourceContextLoaderInterface) { - throw new RuntimeException( - "PicoDeprecated compat plugin '" . __CLASS__ . "' requires a 'Twig_SourceContextLoaderInterface' " - . "Twig loader, '" . get_class($twigLoader) . "' given" - ); - } try { $templatePath = $twigLoader->getSourceContext($templateName)->getPath(); - } catch (\Twig\Error\LoaderError $e) { + } catch (TwigLoaderError $e) { $templatePath = ''; } if ($templatePath) { $themePath = realpath($this->getPico()->getThemesDir() . $this->getPico()->getTheme()) . '/'; - if (substr($templatePath, 0, strlen($themePath)) === $themePath) { + if (substr_compare($templatePath, $themePath, 0, strlen($themePath)) === 0) { $themeApiVersion = $this->getPico()->getThemeApiVersion(); return ($themeApiVersion >= PicoDeprecated::API_VERSION_3) ? $escapeStrategy : false; } @@ -160,11 +173,11 @@ public function twigEscapeStrategy($templateName) * * @return object|null either the matching plugin instance or NULL */ - protected function getPluginFromPath($path) + protected function getPluginFromPath(string $path): ?object { $plugins = $this->getPico()->getPlugins(); foreach ($this->pluginPaths as $pluginName => $pluginPath) { - if ($pluginPath && (substr($path, 0, strlen($pluginPath)) === $pluginPath)) { + if ($pluginPath && (substr_compare($path, $pluginPath, 0, strlen($pluginPath)) === 0)) { return $plugins[$pluginName]; } } @@ -181,13 +194,13 @@ protected function getPluginFromPath($path) $pluginReflector = new ReflectionObject($plugin); $pluginPath = dirname($pluginReflector->getFileName() ?: '') . '/'; - if (in_array($pluginPath, array('/', $rootDir, $vendorDir, $pluginsDir, $themesDir), true)) { + if (in_array($pluginPath, [ '/', $rootDir, $vendorDir, $pluginsDir, $themesDir ], true)) { $pluginPath = ''; } $this->pluginPaths[$pluginName] = $pluginPath; - if ($pluginPath && (substr($path, 0, strlen($pluginPath)) === $pluginPath)) { + if ($pluginPath && (substr_compare($path, $pluginPath, 0, strlen($pluginPath)) === 0)) { return $plugins[$pluginName]; } } @@ -198,7 +211,7 @@ protected function getPluginFromPath($path) /** * {@inheritDoc} */ - public function getApiVersion() + public function getApiVersion(): int { return PicoDeprecated::API_VERSION_3; } diff --git a/plugins/ThemeApi3Plugin.php b/plugins/ThemeApi3Plugin.php new file mode 100644 index 0000000..8a84259 --- /dev/null +++ b/plugins/ThemeApi3Plugin.php @@ -0,0 +1,38 @@ + + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +declare(strict_types=1); + +namespace picocms\PicoDeprecated\Plugin; + +use picocms\PicoDeprecated\AbstractPlugin; +use PicoDeprecated; + +/** + * Maintains backward compatibility with themes using API version 3, written + * for Pico 2.1 + * + * @author Daniel Rudolf + * @link https://picocms.org + * @license https://opensource.org/licenses/MIT The MIT License + * @version 3.0 + */ +class ThemeApi3Plugin extends AbstractPlugin +{ + /** + * {@inheritDoc} + */ + public function getApiVersion(): int + { + return PicoDeprecated::API_VERSION_4; + } +}