Compare commits

...

115 Commits

Author SHA1 Message Date
Andy Miller
972ec26035 prepare for beta release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-22 10:20:44 -06:00
Andy Miller
9116079e97 twig3 compatiblity layer
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-21 11:40:23 -06:00
Andy Miller
51ddb3984c rector casting clarity
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-20 22:49:21 -06:00
Andy Miller
22de638e52 composer updates + php fixes
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-20 22:33:56 -06:00
Andy Miller
365ab93e7e PHP 8.2+ fixes
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-20 22:12:55 -06:00
Andy Miller
c172964025 fix for cache blowing up
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-20 19:16:12 -06:00
Andy Miller
cb0bbcdb8b Deferred support in Twig 3
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-20 18:38:27 -06:00
Andy Miller
35f5d2f329 Merge branch 'develop' into 1.8
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-20 17:57:14 -06:00
Andy Miller
639be5ac0d pages optimizations
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-06-25 16:17:24 -06:00
Andy Miller
d3e32799ab use forked copy of parsedown 1.7.x for PHP 8.4 compatibility
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-04-02 05:34:07 -06:00
Andy Miller
3bebfc6dac fixed for tests
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-04-01 17:03:42 -06:00
Andy Miller
9d80a4d992 upgraded to latest phpdebugbar + fixed browser caching
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-04-01 16:55:29 -06:00
Andy Miller
fc7f72f89d Merge branch 'develop' into 1.8
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-03-31 19:32:54 -06:00
Andy Miller
53391466b0 prepare for beta release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-27 14:08:11 -07:00
Andy Miller
2fadc14c01 Swtiched to forked getgrav/Twig 2.x with PHP 8.4 support
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-27 14:03:31 -07:00
Andy Miller
de2af9e470 Fix empty string causing parse error: fixes #3894
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-24 15:22:35 -07:00
Andy Miller
edfb1a0868 Merge branch 'develop' into 1.8 2025-01-21 14:41:54 +00:00
Andy Miller
9893a605a6 composer update
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-20 11:41:51 +00:00
Andy Miller
83d291c24b 8.2 stuff
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-14 15:55:10 +00:00
Andy Miller
ca1b05ba57 Merge branch 'develop' into 1.8
Signed-off-by: Andy Miller <rhuk@mac.com>

# Conflicts:
#	system/src/Grav/Framework/Collection/AbstractLazyCollection.php
2025-01-06 14:17:08 +00:00
Andy Miller
350e4c04cd test action on 1.8
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-10 14:35:05 -07:00
Andy Miller
d8123a3662 switch to cache@v4 + limit PHP versions
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-10 14:33:29 -07:00
Andy Miller
1e430f635e some more composer updates
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-09 17:32:00 -07:00
Andy Miller
17548131d3 rector fixes for PHP 8.2+
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-09 17:23:56 -07:00
Andy Miller
4a27bd780c vendor updates
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-09 17:14:29 -07:00
Andy Miller
5666d0f211 changelog updated
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-03 15:33:10 -07:00
Andy Miller
d17ab9e06c fixed issue with Abstract Lazy Collection
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-03 15:33:03 -07:00
Andy Miller
a15fe29f43 update version #
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-11-21 12:46:31 -07:00
Andy Miller
3126fa8388 updated changelog
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-11-21 12:43:32 -07:00
Andy Miller
b0c339c9eb moved to stable version of clockwork (v5.3.1)
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-11-21 12:41:56 -07:00
Andy Miller
f812ee8555 more compoer updates
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-11-18 16:13:08 -07:00
Andy Miller
8c6388bb74 package update 2024-10-30 19:26:04 -06:00
Andy Miller
d7aaef986e updated version 2024-10-28 11:43:14 +00:00
Andy Miller
ab9363c478 Merge branch 'develop' into 1.8 2024-10-28 11:32:43 +00:00
Andy Miller
7f2da96c0b update vendor libs 2024-10-28 11:31:20 +00:00
Andy Miller
b16db4b9c0 typo 2024-10-27 12:21:00 +00:00
Andy Miller
42c0682dd8 Merge branch '1.8' of github.com:getgrav/grav into 1.8 2024-10-26 15:25:11 +01:00
Andy Miller
1969ec1876 monolog2 support 2024-10-26 15:25:00 +01:00
Jeremy Gonyea
c30661736c Fix for #3164. Adds aliases as possible commands during lookup (#3863) 2024-10-26 15:18:43 +01:00
Andy Miller
3d2dfa2faf Updated changelog 2024-10-25 20:18:33 +01:00
Andy Miller
f06bbfc563 Missing RocketTheme\Toolbox\Event\EventSubscriberInterface 2024-10-25 20:17:41 +01:00
Andy Miller
37e5526a4f updated changelog 2024-10-25 18:21:23 +01:00
Andy Miller
85c4b8279e fixes for PHP 8.4 - Implicitly nullable parameter declarations deprecated 2024-10-25 18:20:41 +01:00
Andy Miller
46736ce256 upgrade to doctrine/collectons 2.2 2024-10-25 17:53:51 +01:00
Andy Miller
800b2e1ecb updated changelog 2024-10-25 17:39:34 +01:00
Andy Miller
4f065b95a7 updated composer to latest version 2024-10-25 17:33:47 +01:00
Andy Miller
b59a3adc80 avif support via getgrav/image updates 2024-10-25 15:29:16 +01:00
Andy Miller
4ec9a3a489 Merge branch 'develop' into 1.8 2024-10-25 10:49:38 +01:00
Andy Miller
173d08243a use dev-master of Clockwork to support Monolog2/3 2024-10-24 11:58:04 +01:00
Andy Miller
62c60b8ba1 Fixed a couple of monolog deprecations 2024-10-23 17:17:51 +01:00
Andy Miller
59031a8711 use BUILD_SCRIPT_URL_18 in build 2024-10-23 17:07:10 +01:00
Andy Miller
5cd859865f use build-grav-18.sh build script 2024-10-23 16:44:49 +01:00
Andy Miller
16eafbbb04 udpate build.yaml 2024-10-23 14:37:45 +01:00
Andy Miller
3947bb03aa set version properly 2024-10-23 13:14:26 +01:00
Andy Miller
ee55d097f2 set testing true 2024-10-23 13:08:34 +01:00
Andy Miller
ae567469b7 prepare for beta release 2024-10-23 13:08:06 +01:00
Andy Miller
f6decaab15 Merge branch 'develop' into 1.8 2024-10-23 13:04:01 +01:00
Andy Miller
10d36a10bc updated composer.lock 2024-10-23 12:16:29 +01:00
Andy Miller
574a430a10 more composer updates 2024-10-23 12:14:45 +01:00
Andy Miller
302f02ca5d revert schema 2024-10-22 18:01:41 +01:00
Andy Miller
c334479e4c Merge branch 'develop' into feature/v1.8 2024-10-22 15:47:58 +01:00
Andy Miller
b96483c49a Fix tests for latest Codeception version 2024-10-22 13:24:35 +01:00
Andy Miller
cccce836f6 Merge branch 'develop' into feature/v1.8 2024-10-22 12:09:26 +01:00
Andy Miller
bdcb77d429 Merge branch 'develop' into feature/v1.8 2024-10-21 14:20:23 +01:00
Andy Miller
e15cc86716 toAscii() should be static 2024-10-21 14:19:45 +01:00
Andy Miller
dcfbd73d43 twig compatibility stuff 2024-10-14 20:53:07 +01:00
Andy Miller
1967910789 upgrade to latest symfony 6.4 + PHP 8.2 2024-10-14 19:27:43 +01:00
Andy Miller
4f1f9a7755 Merge branch 'develop' into feature/v1.8
# Conflicts:
#	CHANGELOG.md
#	composer.lock
2024-10-14 19:25:17 +01:00
Andy Miller
e4f483998d composer lock file 2023-05-12 13:50:50 -06:00
Andy Miller
7a393101ee Merge branch 'develop' into feature/v1.8
# Conflicts:
#	CHANGELOG.md
#	composer.json
#	composer.lock
#	system/blueprints/config/system.yaml
#	system/src/Grav/Common/Twig/WriteCacheFileTrait.php
2023-05-12 13:44:07 -06:00
Matias Griese
10b15bedf2 Composer update 2022-08-18 13:27:58 +03:00
Matias Griese
8c14a9907e Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.lock
2022-08-18 13:27:06 +03:00
Matias Griese
f490d9a7e1 Fix phpstan error 2022-06-29 13:16:56 +03:00
Matias Griese
81ca0c2e25 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	CHANGELOG.md
	composer.json
	composer.lock
2022-06-29 13:14:06 +03:00
Matias Griese
fbfac9f8f4 Composer update 2022-06-29 13:12:11 +03:00
Matias Griese
d6e72708bf Composer update 2022-06-15 14:41:05 +03:00
Matias Griese
2aff274c31 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.lock
	system/src/Grav/Common/GPM/Remote/AbstractPackageCollection.php
2022-06-15 14:39:38 +03:00
Matias Griese
74c1dfa433 Composer update 2022-05-20 16:48:41 +03:00
Matias Griese
f51a9d9d87 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	CHANGELOG.md
	composer.lock
2022-05-20 16:45:54 +03:00
Matias Griese
e5498f58e6 Composer update 2022-04-19 11:05:19 +03:00
Matias Griese
8f58a4494c Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.lock
2022-04-19 11:04:33 +03:00
Matias Griese
5bfd43256d Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8 2022-03-31 11:31:04 +03:00
Matias Griese
69bc3f7f25 Composer update 2022-03-31 11:27:39 +03:00
Matias Griese
782ceada80 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	CHANGELOG.md
	composer.lock
2022-03-31 11:26:37 +03:00
Matias Griese
36392acbea Composer update 2022-03-23 13:00:19 +02:00
Matias Griese
4b564df38f Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	CHANGELOG.md
2022-03-23 12:58:48 +02:00
Matias Griese
9d179e5b2a Composer update 2022-03-09 12:33:20 +02:00
Matias Griese
6032bd07dc Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.json
	composer.lock
2022-03-09 12:32:31 +02:00
Matias Griese
9a87a509b0 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8 2022-02-22 11:35:29 +02:00
Matias Griese
46f2a81b21 Phpstan fixes 2022-02-19 15:20:06 +02:00
Matias Griese
f5e21645f6 Support phpstan level 6 in Framework classes 2022-02-19 14:17:02 +02:00
Matias Griese
12c8cf9c40 Phpstan fixes 2022-02-19 13:47:29 +02:00
Matias Griese
93bb929b38 Phpstan updates 2022-02-19 13:17:34 +02:00
Matias Griese
85eaf308d5 Fixed FlexDirectory::getCache() after converting to Symfony Cache 2022-02-19 13:17:19 +02:00
Matias Griese
d9ede28b99 Composer update 2022-02-19 12:18:40 +02:00
Matias Griese
2e65b0eea4 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.lock
2022-02-19 12:18:00 +02:00
Matias Griese
7660a80ef7 Use older monolog due to clockwork incompatibility 2022-02-16 09:51:09 +02:00
Matias Griese
6d0a436834 Changelog update (pt 2) 2022-02-12 16:58:07 +02:00
Matias Griese
176fd8f1d8 Changelog update 2022-02-12 16:52:25 +02:00
Matias Griese
2f85fe9c99 Move unmaintained/unused vendor dependencies to the end of the list 2022-02-12 16:49:09 +02:00
Matias Griese
d93d297dc4 Updated to **Monolog 2.3** 2022-02-12 16:36:58 +02:00
Matias Griese
fcd9093f84 Use **Symfony Cache** instead of unmaintaided **Doctrine Cache** (with backward compatibility layer) 2022-02-12 15:33:38 +02:00
Matias Griese
58b54a70bd Removed system.umask_fix setting for security reasons 2022-02-12 13:49:30 +02:00
Matias Griese
9daa0a9041 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.lock
2022-02-12 13:08:23 +02:00
Matias Griese
965e03daf2 Update dependencies so that everything works again 2022-02-07 14:14:11 +02:00
Matias Griese
b6c3db082a Update composer dependencies 2022-02-07 14:03:05 +02:00
Matias Griese
26b68953c4 Composer update 2022-02-07 13:48:47 +02:00
Matias Griese
fba015c5d9 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.json
	composer.lock
2022-02-07 13:47:41 +02:00
Matias Griese
7223c177c4 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.json
	composer.lock
2021-12-08 10:08:34 +02:00
Matias Griese
a68bdd2b75 Fixed Toolbox Event 2021-11-25 14:17:13 +02:00
Matias Griese
38e4624506 Composer update 2021-11-25 11:51:40 +02:00
Matias Griese
ad9287ee0f Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.json
	composer.lock
2021-11-25 11:46:21 +02:00
Matias Griese
777ac119de Update all libraries (WIP) 2021-10-20 20:33:05 +03:00
Matias Griese
076c64841e Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8 2021-10-20 20:28:50 +03:00
Matias Griese
62cb40fef5 Composer update 2021-10-20 20:28:24 +03:00
313 changed files with 6339 additions and 5159 deletions

View File

@@ -11,7 +11,7 @@ jobs:
permissions:
contents: write # for release creation (svenstaro/upload-release-action)
if: "!github.event.release.prerelease"
#if: "!github.event.release.prerelease"
runs-on: ubuntu-latest
steps:
@@ -23,7 +23,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 7.3
php-version: 8.2
extensions: opcache, gd
tools: composer:v2
coverage: none
@@ -38,10 +38,10 @@ jobs:
- name: Retrieval of Builder Scripts
run: |
# Real Grav URL
curl --silent -H "Authorization: token ${{ secrets.GLOBAL_TOKEN }}" -H "Accept: application/vnd.github.v3.raw" ${{ secrets.BUILD_SCRIPT_URL }} --output build-grav.sh
curl --silent -H "Authorization: token ${{ secrets.GLOBAL_TOKEN }}" -H "Accept: application/vnd.github.v3.raw" ${{ secrets.BUILD_SCRIPT_URL_18 }} --output build-grav.sh
# Development Local URL
# curl ${{ secrets.BUILD_SCRIPT_URL }} --output build-grav.sh
# curl ${{ secrets.BUILD_SCRIPT_URL_18 }} --output build-grav.sh
- name: Grav Builder
run: |

View File

@@ -2,9 +2,9 @@ name: PHP Tests
on:
push:
branches: [ develop ]
branches: [ develop, 1.8 ]
pull_request:
branches: [ develop ]
branches: [ develop, 1.8 ]
permissions:
contents: read # to fetch code (actions/checkout)
@@ -13,7 +13,7 @@ jobs:
unit-tests:
strategy:
matrix:
php: ['8.3', '8.2', '8.1', '8.0', '7.4', '7.3']
php: [8.4, 8.3, 8.2]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}

View File

@@ -10,7 +10,7 @@ on:
admin:
description: 'Create also a package with Admin'
required: true
default: true
default: 'true'
permissions:
contents: read # to fetch code (actions/checkout)

View File

@@ -1,3 +1,61 @@
# v1.8.0-beta.5
## 09/22/2025
1. [](#bugfix)
* Deferred Extension support in Forked version of Twig 3
* Fix for cache blowing up when upgrading from 1.7 to 1.8 via CLI
1. [](#new)
* Added separate `strict_mode.twig2_compat` and `strict_mode.twig3_compat` toggles to manage auto-escape behaviour and automatic Twig 3 compatible template rewrites
# v1.8.0-beta.4
## 01/27/2025
1. [](#bugfix)
* Fixed a PHP compatibility issue with `AbstractLazyCollection`
1. [](#improved)
* Global PHP 8.2 code optimizations
* More PHP 8.4 compatibility fixes
* Twig 2.x forked to getgrav/twig 2.x for PHP 8.4 compatibility
* Switch to cache@v4 + limit PHP version for Github actions
* Trigger testing Github action for Grav 1.8
* Merge latest Grav 1.7 fixes into Grav 1.8
# v1.8.0-beta.3
## 11/21/2024
1. [](#improved)
* Updated composer libraries to latest versions for compatibility fixes
# v1.8.0-beta.2
## 10/28/2024
1. [](#new)
* Use `dev-master` branch of Clockwork to support Monolog2 / Monolog3
* `AVIF` image support via updates to `getgrav/Image` library
* Upgraded to **Doctrine Collection 2.2**
1. [](#improved)
* Updated composer libraries
* Updated composer.php binary to `v2.8.1`
* Fixes for PHP 8.4 - Implicitly nullable parameter declarations deprecated
* Added back Missing `RocketTheme\Toolbox\Event\EventSubscriberInterface` for Gantry5
1. [](#bugfix)
* Various fixes to use `$log->debug()`, `$log->info()`, `$log->warning()` and `$log->error()` For Monolog2 support
# v1.8.0-beta.1
## 10/23/2024
1. [](#new)
* Set minimum requirements to **PHP 8.2**
* Updated to **Twig 2.14**
* Updated to **Symfony 6.4**
* Updated to **Monolog 2.3**
* Updated to **RocketTheme/Toolbox 2.0**
* Updated to **Composer/Semver 3.2**
* Use **Symfony Cache** instead of unmaintained **Doctrine Cache**
* Removed unsupported **APC**, **WinCache**, **XCache** and **Memcache**, use apcu or memcached instead
* Removed `system.umask_fix` setting for security reasons
* Support phpstan level 6 in Framework classes
# v1.7.49.5
## 09/10/2025
@@ -49,6 +107,7 @@
* Bug in `exif_read_data` [#3878](https://github.com/getgrav/grav/pull/3878)
* Fix parser error in URI: [#3894](https://github.com/getgrav/grav/issues/3894)
>>>>>>> develop
# v1.7.48
## 10/28/2024
@@ -64,18 +123,18 @@
## 10/23/2024
1. [](#new)
* New `Utils::toAscii()` method
* Added support for Clockwork Debugger to allow web UI (requires new `clockwork-web` plugin)
* New `Utils::toAscii()` method
* Added support for Clockwork Debugger to allow web UI (requires new `clockwork-web` plugin)
1. [](#improved)
* Include modular sub-pages in last-modification date computation [#3562](https://github.com/getgrav/grav/pull/3562)
* Updated vendor libs to latest versions
* Updated JQuery to `3.7.1` [#3787](https://github.com/getgrav/grav/pull/3827)
* Updated vendor libraries to latest versions
* Support for Fediverse Creator meta tag [#3844](https://github.com/getgrav/grav/pull/3844)
* Include modular sub-pages in last-modification date computation [#3562](https://github.com/getgrav/grav/pull/3562)
* Updated vendor libs to latest versions
* Updated JQuery to `3.7.1` [#3787](https://github.com/getgrav/grav/pull/3827)
* Updated vendor libraries to latest versions
* Support for Fediverse Creator meta tag [#3844](https://github.com/getgrav/grav/pull/3844)
1. [](#bugfix)
* Fixes deprecated for return type in Filesystem with PHP 8.3.6 [#3831](https://github.com/getgrav/grav/issues/3831)
* Fix for `exif_imagtetype()` throwing an exception when file doesn't exist
* Fix JSON output comments check with content type [#3859](https://github.com/getgrav/grav/pull/3859)
* Fixes deprecated for return type in Filesystem with PHP 8.3.6 [#3831](https://github.com/getgrav/grav/issues/3831)
* Fix for `exif_imagtetype()` throwing an exception when file doesn't exist
* Fix JSON output comments check with content type [#3859](https://github.com/getgrav/grav/pull/3859)
# v1.7.46
## 05/15/2024

View File

@@ -20,7 +20,7 @@ The underlying architecture of Grav is designed to use well-established and _bes
# Requirements
- PHP 7.3.6 or higher. Check the [required modules list](https://learn.getgrav.org/basics/requirements#php-requirements)
- PHP 8.2 or higher. Check the [required modules list](https://learn.getgrav.org/basics/requirements#php-requirements)
- Check the [Apache](https://learn.getgrav.org/basics/requirements#apache-requirements) or [IIS](https://learn.getgrav.org/basics/requirements#iis-requirements) requirements
# Documentation
@@ -89,9 +89,10 @@ bin/gpm update
## Upgrading from older version
* [Upgrading to Grav 1.8](https://learn.getgrav.org/16/advanced/grav-development/grav-18-upgrade-guide)
* [Upgrading to Grav 1.7](https://learn.getgrav.org/16/advanced/grav-development/grav-17-upgrade-guide)
* [Upgrading to Grav 1.6](https://learn.getgrav.org/16/advanced/grav-development/grav-16-upgrade-guide)
* [Upgrading from Grav <1.6](https://learn.getgrav.org/16/advanced/grav-development/grav-15-upgrade-guide)
* [Upgrading from Grav before 1.6](https://learn.getgrav.org/16/advanced/grav-development/grav-15-upgrade-guide)
# Contributing
We appreciate any contribution to Grav, whether it is related to bugs, grammar, or simply a suggestion or improvement! Please refer to the [Contributing guide](CONTRIBUTING.md) for more guidance on this topic.

Binary file not shown.

View File

@@ -2,7 +2,7 @@ actor: Tester
bootstrap: _bootstrap.php
paths:
tests: tests
log: tests/_output
output: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs

View File

@@ -12,7 +12,7 @@
"homepage": "https://getgrav.org",
"license": "MIT",
"require": {
"php": "^7.3.6 || ^8.0",
"php": "^8.2",
"ext-json": "*",
"ext-openssl": "*",
"ext-curl": "*",
@@ -20,61 +20,79 @@
"ext-dom": "*",
"ext-libxml": "*",
"ext-gd": "*",
"symfony/polyfill-mbstring": "~1.23",
"symfony/polyfill-iconv": "^1.23",
"symfony/polyfill-php74": "^1.23",
"symfony/polyfill-php80": "^1.23",
"symfony/polyfill-php81": "^1.23",
"symfony/polyfill-mbstring": "^1.24",
"symfony/polyfill-iconv": "^1.24",
"symfony/polyfill-php80": "^1.24",
"symfony/polyfill-php81": "^1.24",
"psr/simple-cache": "^1.0",
"psr/http-message": "^1.0",
"psr/http-message": "^1.1",
"psr/http-server-middleware": "^1.0",
"psr/container": "~1.1.0",
"nyholm/psr7-server": "^1.0",
"nyholm/psr7": "^1.3",
"twig/twig": "~v1.44",
"psr/container": "^1.1",
"psr/log": "^1.1",
"symfony/cache": "^6.4",
"symfony/yaml": "^6.4",
"symfony/console": "^6.4",
"symfony/event-dispatcher": "^6.4",
"symfony/var-exporter": "^6.4",
"symfony/var-dumper": "^6.4",
"symfony/process": "^6.4",
"symfony/http-client": "^6.4",
"twig/twig": "3.x-dev",
"monolog/monolog": "^2.0",
"doctrine/cache": "^2.2",
"doctrine/collections": "^2.2",
"pimple/pimple": "~3.5.0",
"nyholm/psr7-server": "^1.1",
"nyholm/psr7": "^1.8",
"erusev/parsedown": "^1.7",
"erusev/parsedown-extra": "~0.8",
"symfony/contracts": "~1.1",
"symfony/yaml": "~4.4",
"symfony/console": "~4.4",
"symfony/event-dispatcher": "~4.4",
"symfony/var-dumper": "~4.4",
"symfony/process": "~4.4",
"doctrine/cache": "^1.10",
"doctrine/collections": "^1.6",
"guzzlehttp/psr7": "^1.7",
"filp/whoops": "~2.9",
"rockettheme/toolbox": "v2.x-dev",
"composer/ca-bundle": "^1.5",
"composer/semver": "^3.4",
"dragonmantank/cron-expression": "^3.3",
"willdurand/negotiation": "^3.1",
"rhukster/dom-sanitizer": "^1.0",
"matthiasmullie/minify": "^1.3",
"monolog/monolog": "~1.25",
"donatj/phpuseragentparser": "~1.9",
"guzzlehttp/psr7": "^2.7",
"filp/whoops": "~2.16",
"itsgoingd/clockwork": "^5.3",
"php-debugbar/php-debugbar": "~2.1",
"getgrav/image": "^4.0",
"getgrav/cache": "^2.0",
"donatj/phpuseragentparser": "~1.1",
"pimple/pimple": "~3.5.0",
"rockettheme/toolbox": "~1.5",
"maximebf/debugbar": "~1.16",
"league/climate": "^3.6",
"antoligy/dom-string-iterators": "^1.0",
"miljar/php-exif": "^0.6",
"composer/ca-bundle": "^1.2",
"dragonmantank/cron-expression": "^3.3",
"willdurand/negotiation": "^3.0",
"itsgoingd/clockwork": "^5.0",
"symfony/http-client": "^4.4",
"composer/semver": "^1.4",
"rhukster/dom-sanitizer": "^1.0",
"league/climate": "^3.10",
"multiavatar/multiavatar-php": "^1.0"
},
"require-dev": {
"codeception/codeception": "^4.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-deprecation-rules": "^1.0",
"codeception/codeception": "^5.1",
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-deprecation-rules": "^2.0",
"phpunit/php-code-coverage": "~9.2",
"getgrav/markdowndocs": "^2.0",
"codeception/module-asserts": "^1.3",
"codeception/module-phpbrowser": "^1.0"
"codeception/module-asserts": "*",
"codeception/module-phpbrowser": "*",
"rector/rector": "^2.1"
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/rockettheme/toolbox"
},
{
"type": "vcs",
"url": "https://github.com/getgrav/twig"
},
{
"type": "vcs",
"url": "https://github.com/getgrav/parsedown"
}
],
"replace": {
"symfony/polyfill-php72": "*",
"symfony/polyfill-php73": "*"
"symfony/polyfill-php73": "*",
"symfony/polyfill-php74": "*"
},
"suggest": {
"ext-mbstring": "Recommended for better performance",
@@ -87,11 +105,16 @@
"ext-exif": "Needed to use exif data from images."
},
"config": {
"apcu-autoloader": true
"apcu-autoloader": true,
"platform": {
"php": "8.2"
}
},
"autoload": {
"psr-4": {
"Grav\\": "system/src/Grav",
"Doctrine\\": "system/src/Doctrine",
"RocketTheme\\": "system/src/RocketTheme",
"Twig\\": "system/src/Twig"
},
"files": [
@@ -111,10 +134,12 @@
]
},
"scripts": {
"api-17": "vendor/bin/phpdoc-md generate system/src > user/pages/14.api/default.17.md",
"api-18": "vendor/bin/phpdoc-md generate system/src > user/pages/14.api/default.18.md",
"post-create-project-cmd": "bin/grav install",
"rector": "vendor/bin/rector",
"rector:php-compat": "@php vendor/bin/rector process --config=system/rector.php --ansi --no-progress-bar",
"phpstan": "vendor/bin/phpstan analyse -l 2 -c ./tests/phpstan/phpstan.neon --memory-limit=720M system/src",
"phpstan-framework": "vendor/bin/phpstan analyse -l 5 -c ./tests/phpstan/phpstan.neon --memory-limit=480M system/src/Grav/Framework system/src/Grav/Events system/src/Grav/Installer",
"phpstan-framework": "vendor/bin/phpstan analyse -l 6 -c ./tests/phpstan/phpstan.neon --memory-limit=480M system/src/Grav/Framework system/src/Grav/Events system/src/Grav/Installer",
"phpstan-plugins": "vendor/bin/phpstan analyse -l 1 -c ./tests/phpstan/plugins.neon --memory-limit=400M user/plugins",
"test": "vendor/bin/codecept run unit",
"test-windows": "vendor\\bin\\codecept run unit"

2776
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,7 @@
namespace Grav;
\define('GRAV_REQUEST_TIME', microtime(true));
\define('GRAV_PHP_MIN', '7.3.6');
\define('GRAV_PHP_MIN', '8.2.0');
if (PHP_SAPI === 'cli-server') {
$symfony_server = stripos(getenv('_'), 'symfony') !== false || stripos($_SERVER['SERVER_SOFTWARE'] ?? '', 'symfony') !== false || stripos($_ENV['SERVER_SOFTWARE'] ?? '', 'symfony') !== false;
@@ -40,12 +40,12 @@ use Grav\Common\Grav;
use RocketTheme\Toolbox\Event\Event;
// Get the Grav instance
$grav = Grav::instance(array('loader' => $loader));
$grav = Grav::instance(['loader' => $loader]);
// Process the page
try {
$grav->process();
} catch (\Error|\Exception $e) {
$grav->fireEvent('onFatalException', new Event(array('exception' => $e)));
$grav->fireEvent('onFatalException', new Event(['exception' => $e]));
throw $e;
}

View File

@@ -1,67 +1,5 @@
div.phpdebugbar {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
div.phpdebugbar a.phpdebugbar-restore-btn::after {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAA/1BMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeHh4AAAD///8EBAT7+/sLCwv29vYVFRUvLy/t7e3m5ubCwsKxsbE/Pz+mpqZMTEwcHBzy8vLp6emfn5+AgIA2Njbi4uLf39+rq6tzc3NWVlYhISHa2trW1tbS0tLMzMy7u7uZmZmUlJSMjIxvb29kZGRHR0c7Ozt5eXkqKiq1tbWQkJBqampbW1tSUlLHx8eHh4ckJCRDQ0M3wD42AAAAI3RSTlMA/PibTbQ0x76TVAlw4LhZLOuEYCAN9Hjx0a2ppGZEGYw97djhXHwAAATZSURBVFjDlVcHW+MwDO1eFCjj2McNOzvdpXTTXVbL/P+/5SQ7QSSX5Di1X1onfi/Sk+Q4sTDbKqWK+YuznZ2zi3wxVdqK/Zf92M1nT9gnO8rmd398GX6Z3xaoOFoiAQcx3E5efgmeSuN8F6Xg1x3G06l/wjNpMR1B0uif4EhnIuFb+0diIoFXk3IVfokisR+h52GO4JKgyjmfaMhAFNlSaPR7DpwI+lzn/E4QKIqmKIJirxCMP4izBPPZPXhgXwMBYgULw0nfg/BF5scDbslb7QeJ08yqqTEmGYoB95d4H8ETL8+n9wBqrLu6ao3bBsMwAnxISf/9BHcqxNB8Y7cWl3Zz7TAUfPrvAT6AoNEFFXvsjutL01yOuMrtBxnFXsmT/1wQHmdWAFNnI3uI48Yj0FUcHbKf62GfUfr8eeQt7Uk3mQZpZNoVRPEui5vtEz5zFEpgWnyqVBZMc6oaGNriH2hGVZ0OxEvInPeMaZWJBA7vmPbCr5jjws5HBnAUxvDMH40aCIf4G5BjRQSs8E8HFFYf8bGxgDvD55bzGhwWkoBcuIyHR/AMdaCagxXDhtL6tSqoWpd4BMnlIR+Or+rYTK/a3EAGcc6e4AWHISnWv20iCCojsHoVlQdjrMexFF2C7UMg2A2WEGWbQhXN6l3eXC6XGp4b9qxbuEB2EBGBwtocrK90cVG5mbRXm6vmx/0phq1sIAGKDgLOBiN1MrO5a9aDl+D0W6x0Ar9BCTRuIIANa90Y7LrLVRXzwVtDInCqMRWcf2bUOEAsa4wJqFowQALL9EiAtVRk8QC4OW+1pOM9jIaVASwYagyNXDj+W0NcfuZNzjtXOiL0Zzg30Llj+ptfxQs4+vBPNiL5PawFCBkgXpUaVtqGl+A8dgZHL34BcBUQrwPptToW+o37Ku+UH9eYByJIx3YkAeFnMFuGO7S5gEp7YhXxa5OOAM39RXDPXb0qmpROsswZe+twXdU55oUIZAiEv3bD1UFwIYKkmGqytPCDCwKFQCKK0yL7qtSAPX54UAbtsLuBHkb9zyLmPQSNjsSgmQwKUOIfEY8F8t4B34DvndJY9BA8tNBJq1Nev9axmaStFcQLhgYoCTo0salkIaW8OUDdWjMTR2sHPhrAFZqx6cqcKE4pl2BJJ4K6hfwvqNgAnXfKX/HU6X3Zrhnu0k7tLNZtTBRv1hkwTDBY1NzFU6doDYjJbWdQkQhWwuU7/LvhTh3SDoco4ECL4i5dwURbc8NdDZz2IwKicE8d0KIqWetLE3+lL4hvUuGSeRfVWNLfj/gpOw4smBJBkKQHCzlHGwvAj4woB1gq5NGGLSXtORBPnUQPV5/MPVkDMxbpwG7w4x0xL6Ltxka0A/4NBvV09UVk4DoSn/jl2+JQS9q9KYawisAD4CfhsZ4TH3htylsdEHARIQBusqCKyUpymycgbbkkXEXjT3z7/oKQFTFVuZD2FMJHZIDsO5x2d4aAr2jR+GLwZhtAb028/0yJ9J8dE87jQyKObcjtTXT8dH+fDuKF4/eiPwzH44wTf/yUi6wrpRIOZ9lM1EtXAifFI+CJn9+iX/t2xMQwOMth/UZbASi8btAwR9FHWSpJr75g9Oqbin3VDg+SpwlP6k6TB4ex/7JvmcJx8jydy6XPk8eFTKhyfwCgX71MSvaBHgAAAABJRU5ErkJggg==) !important;
width: 32px;
}
.phpdebugbar pre {
padding: 1rem;
}
.phpdebugbar div.phpdebugbar-header > div > * {
padding: 5px 15px;
}
.phpdebugbar div.phpdebugbar-header > div.phpdebugbar-header-right > * {
padding: 5px 8px;
}
.phpdebugbar a.phpdebugbar-restore-btn {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAA/1BMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeHh4AAAD///8EBAT7+/sLCwv29vYVFRUvLy/t7e3m5ubCwsKxsbE/Pz+mpqZMTEwcHBzy8vLp6emfn5+AgIA2Njbi4uLf39+rq6tzc3NWVlYhISHa2trW1tbS0tLMzMy7u7uZmZmUlJSMjIxvb29kZGRHR0c7Ozt5eXkqKiq1tbWQkJBqampbW1tSUlLHx8eHh4ckJCRDQ0M3wD42AAAAI3RSTlMA/PibTbQ0x76TVAlw4LhZLOuEYCAN9Hjx0a2ppGZEGYw97djhXHwAAATZSURBVFjDlVcHW+MwDO1eFCjj2McNOzvdpXTTXVbL/P+/5SQ7QSSX5Di1X1onfi/Sk+Q4sTDbKqWK+YuznZ2zi3wxVdqK/Zf92M1nT9gnO8rmd398GX6Z3xaoOFoiAQcx3E5efgmeSuN8F6Xg1x3G06l/wjNpMR1B0uif4EhnIuFb+0diIoFXk3IVfokisR+h52GO4JKgyjmfaMhAFNlSaPR7DpwI+lzn/E4QKIqmKIJirxCMP4izBPPZPXhgXwMBYgULw0nfg/BF5scDbslb7QeJ08yqqTEmGYoB95d4H8ETL8+n9wBqrLu6ao3bBsMwAnxISf/9BHcqxNB8Y7cWl3Zz7TAUfPrvAT6AoNEFFXvsjutL01yOuMrtBxnFXsmT/1wQHmdWAFNnI3uI48Yj0FUcHbKf62GfUfr8eeQt7Uk3mQZpZNoVRPEui5vtEz5zFEpgWnyqVBZMc6oaGNriH2hGVZ0OxEvInPeMaZWJBA7vmPbCr5jjws5HBnAUxvDMH40aCIf4G5BjRQSs8E8HFFYf8bGxgDvD55bzGhwWkoBcuIyHR/AMdaCagxXDhtL6tSqoWpd4BMnlIR+Or+rYTK/a3EAGcc6e4AWHISnWv20iCCojsHoVlQdjrMexFF2C7UMg2A2WEGWbQhXN6l3eXC6XGp4b9qxbuEB2EBGBwtocrK90cVG5mbRXm6vmx/0phq1sIAGKDgLOBiN1MrO5a9aDl+D0W6x0Ar9BCTRuIIANa90Y7LrLVRXzwVtDInCqMRWcf2bUOEAsa4wJqFowQALL9EiAtVRk8QC4OW+1pOM9jIaVASwYagyNXDj+W0NcfuZNzjtXOiL0Zzg30Llj+ptfxQs4+vBPNiL5PawFCBkgXpUaVtqGl+A8dgZHL34BcBUQrwPptToW+o37Ku+UH9eYByJIx3YkAeFnMFuGO7S5gEp7YhXxa5OOAM39RXDPXb0qmpROsswZe+twXdU55oUIZAiEv3bD1UFwIYKkmGqytPCDCwKFQCKK0yL7qtSAPX54UAbtsLuBHkb9zyLmPQSNjsSgmQwKUOIfEY8F8t4B34DvndJY9BA8tNBJq1Nev9axmaStFcQLhgYoCTo0salkIaW8OUDdWjMTR2sHPhrAFZqx6cqcKE4pl2BJJ4K6hfwvqNgAnXfKX/HU6X3Zrhnu0k7tLNZtTBRv1hkwTDBY1NzFU6doDYjJbWdQkQhWwuU7/LvhTh3SDoco4ECL4i5dwURbc8NdDZz2IwKicE8d0KIqWetLE3+lL4hvUuGSeRfVWNLfj/gpOw4smBJBkKQHCzlHGwvAj4woB1gq5NGGLSXtORBPnUQPV5/MPVkDMxbpwG7w4x0xL6Ltxka0A/4NBvV09UVk4DoSn/jl2+JQS9q9KYawisAD4CfhsZ4TH3htylsdEHARIQBusqCKyUpymycgbbkkXEXjT3z7/oKQFTFVuZD2FMJHZIDsO5x2d4aAr2jR+GLwZhtAb028/0yJ9J8dE87jQyKObcjtTXT8dH+fDuKF4/eiPwzH44wTf/yUi6wrpRIOZ9lM1EtXAifFI+CJn9+iX/t2xMQwOMth/UZbASi8btAwR9FHWSpJr75g9Oqbin3VDg+SpwlP6k6TB4ex/7JvmcJx8jydy6XPk8eFTKhyfwCgX71MSvaBHgAAAABJRU5ErkJggg==);
width: 13px;
}
.phpdebugbar a.phpdebugbar-tab.phpdebugbar-active {
background: #3DB9EC;
color: #fff;
margin-top: -1px;
padding-top: 6px;
}
.phpdebugbar .phpdebugbar-widgets-toolbar {
border-top: 1px solid #ddd;
padding-left: 5px;
padding-right: 2px;
padding-top: 2px;
background-color: #fafafa !important;
width: auto !important;
left: 0;
right: 0;
}
.phpdebugbar .phpdebugbar-widgets-toolbar input {
background: transparent !important;
}
.phpdebugbar .phpdebugbar-widgets-toolbar .phpdebugbar-widgets-filter {
}
.phpdebugbar input[type=text] {
padding: 0;
display: inline;
}
.phpdebugbar dl.phpdebugbar-widgets-varlist, ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-label {
font-family: "DejaVu Sans Mono", Menlo, Monaco, Consolas, Courier, monospace;
font-size: 12px;
}
ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-label {
text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff;
top: 0;
}
.phpdebugbar pre, .phpdebugbar code {
margin: 0;
font-size: 14px;
}

View File

@@ -619,11 +619,9 @@ form:
options:
auto: Auto detect
file: File
apc: APC
apcu: APCu
memcache: Memcache
memcached: Memcached
wincache: WinCache
redis: Redis
cache.prefix:
@@ -720,20 +718,6 @@ form:
validate:
type: bool
cache.memcache.server:
type: text
size: medium
label: PLUGIN_ADMIN.MEMCACHE_SERVER
help: PLUGIN_ADMIN.MEMCACHE_SERVER_HELP
placeholder: "localhost"
cache.memcache.port:
type: text
size: small
label: PLUGIN_ADMIN.MEMCACHE_PORT
help: PLUGIN_ADMIN.MEMCACHE_PORT_HELP
placeholder: "11211"
cache.memcached.server:
type: text
size: medium
@@ -791,8 +775,8 @@ form:
flex.cache.index.enabled:
type: toggle
label: PLUGIN_ADMIN.FLEX_INDEX_CACHE_ENABLED
highlight: 1
default: 1
highlight: 0
default: 0
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
@@ -809,8 +793,8 @@ form:
flex.cache.object.enabled:
type: toggle
label: PLUGIN_ADMIN.FLEX_OBJECT_CACHE_ENABLED
highlight: 1
default: 1
highlight: 0
default: 0
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
@@ -897,17 +881,6 @@ form:
validate:
type: bool
twig.umask_fix:
type: toggle
label: PLUGIN_ADMIN.TWIG_UMASK_FIX
help: PLUGIN_ADMIN.TWIG_UMASK_FIX_HELP
highlight: 0
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
assets:
type: tab
title: PLUGIN_ADMIN.ASSETS
@@ -1783,8 +1756,8 @@ form:
http_x_forwarded.host:
type: toggle
label: HTTP_X_FORWARDED_HOST Enabled
highlight: 0
default: 0
highlight: 1
default: 1
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
@@ -1817,8 +1790,8 @@ form:
strict_mode.blueprint_compat:
type: toggle
label: PLUGIN_ADMIN.STRICT_BLUEPRINT_COMPAT
highlight: 0
default: 0
highlight: 1
default: 1
help: PLUGIN_ADMIN.STRICT_BLUEPRINT_COMPAT_HELP
options:
1: PLUGIN_ADMIN.YES
@@ -1838,7 +1811,7 @@ form:
validate:
type: bool
strict_mode.twig_compat:
strict_mode.twig2_compat:
type: toggle
label: PLUGIN_ADMIN.STRICT_TWIG_COMPAT
highlight: 0
@@ -1850,6 +1823,18 @@ form:
validate:
type: bool
strict_mode.twig3_compat:
type: toggle
label: Twig 3 Compatibility
highlight: 0
default: 0
help: Enable automatic rewrites for legacy Twig 1/2 syntax that breaks on Twig 3 (e.g. `for ... if ...` guards)
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
accounts:
type: tab
@@ -1912,6 +1897,3 @@ form:
#
# pages.type:
# type: hidden

File diff suppressed because it is too large Load Diff

View File

@@ -93,13 +93,13 @@ cache:
enabled: true # Set to true to enable caching
check:
method: file # Method to check for updates in pages: file|folder|hash|none
driver: auto # One of: auto|file|apcu|memcache|wincache
driver: auto # One of: auto|file|apcu|memcached|redis
prefix: 'g' # Cache prefix string (prevents cache conflicts)
purge_at: '0 4 * * *' # How often to purge old file cache (using new scheduler)
clear_at: '0 3 * * *' # How often to clear cache (using new scheduler)
clear_job_type: 'standard' # Type to clear when processing the scheduled clear job `standard`|`all`
clear_images_by_default: false # By default grav does not include processed images in cache clear, this can be enabled
cli_compatibility: false # Ensures only non-volatile drivers are used (file, redis, memcache, etc.)
cli_compatibility: false # Ensures only non-volatile drivers are used (file, redis, memcached, etc.)
lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite)
purge_max_age_days: 30 # Maximum age of cache items in days before they are purged
gzip: false # GZip compress the page output
@@ -118,7 +118,6 @@ twig:
undefined_filters: true # Allow undefined filters
safe_functions: [] # List of PHP functions which are allowed to be used as Twig functions
safe_filters: [] # List of PHP functions which are allowed to be used as Twig filters
umask_fix: false # By default Twig creates cached files as 755, fix switches this to 775
assets: # Configuration for Assets Manager (JS, CSS)
css_pipeline: false # The CSS pipeline is the unification of multiple CSS resources into one file
@@ -231,5 +230,6 @@ flex:
strict_mode:
yaml_compat: false # Set to true to enable YAML backwards compatibility
twig_compat: false # Set to true to enable deprecated Twig settings (autoescape: false)
twig2_compat: false # Set to true to enable deprecated Twig settings (autoescape: false)
twig3_compat: true # Set to true to enable automatic fixes for Twig 3 syntax changes
blueprint_compat: false # Set to true to enable backward compatible strict support for blueprints

View File

@@ -9,13 +9,13 @@
// Some standard defines
define('GRAV', true);
define('GRAV_VERSION', '1.7.49.5');
define('GRAV_SCHEMA', '1.7.0_2020-11-20_1');
define('GRAV_TESTING', false);
define('GRAV_VERSION', '1.8.0-beta.5');
define('GRAV_SCHEMA', '1.8.0_2025-09-21_0');
define('GRAV_TESTING', true);
// PHP minimum requirement
if (!defined('GRAV_PHP_MIN')) {
define('GRAV_PHP_MIN', '7.3.6');
define('GRAV_PHP_MIN', '8.2.0');
}
// Directory separator

16
system/rector.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
use Rector\Config\RectorConfig;
return RectorConfig::configure()
->withSkip([
__DIR__ . '/vendor',
])
->withPaths([
__DIR__
])
->withPhpSets(php82: true)
->withPhpVersion(Rector\ValueObject\PhpVersion::PHP_84)
->withRules([
Rector\Php84\Rector\Param\ExplicitNullableParamTypeRector::class,
]);

View File

@@ -18,17 +18,17 @@ $path = $_SERVER['SCRIPT_NAME'];
if ($path !== '/index.php' && is_file($root . $path)) {
if (!(
// Block all direct access to files and folders beginning with a dot
strpos($path, '/.') !== false
str_contains((string) $path, '/.')
// Block all direct access for these folders
|| preg_match('`^/(\.git|cache|bin|logs|backup|webserver-configs|tests)/`ui', $path)
|| preg_match('`^/(\.git|cache|bin|logs|backup|webserver-configs|tests)/`ui', (string) $path)
// Block access to specific file types for these system folders
|| preg_match('`^/(system|vendor)/(.*)\.(txt|xml|md|html|json|yaml|yml|php|pl|py|cgi|twig|sh|bat)$`ui', $path)
|| preg_match('`^/(system|vendor)/(.*)\.(txt|xml|md|html|json|yaml|yml|php|pl|py|cgi|twig|sh|bat)$`ui', (string) $path)
// Block access to specific file types for these user folders
|| preg_match('`^/(user)/(.*)\.(txt|md|json|yaml|yml|php|pl|py|cgi|twig|sh|bat)$`ui', $path)
|| preg_match('`^/(user)/(.*)\.(txt|md|json|yaml|yml|php|pl|py|cgi|twig|sh|bat)$`ui', (string) $path)
// Block all direct access to .md files
|| preg_match('`\.md$`ui', $path)
|| preg_match('`\.md$`ui', (string) $path)
// Block access to specific files in the root folder
|| preg_match('`^/(LICENSE\.txt|composer\.lock|composer\.json|\.htaccess)$`ui', $path)
|| preg_match('`^/(LICENSE\.txt|composer\.lock|composer\.json|\.htaccess)$`ui', (string) $path)
)) {
return false;
}

View File

@@ -0,0 +1,93 @@
<?php
namespace Doctrine\Common\Cache;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
/**
* Filesystem cache driver (backwards compatibility).
*/
class FilesystemCache extends CacheProvider
{
public const EXTENSION = '.doctrinecache.data';
/** @var FilesystemAdapter */
private $pool;
/**
* {@inheritdoc}
*/
public function __construct($directory, $extension = self::EXTENSION, $umask = 0002)
{
user_error(self::class . ' is deprecated since Grav 1.8, use Symfony cache instead', E_USER_DEPRECATED);
$this->pool = new FilesystemAdapter('', 0, $directory);
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
$item = $this->pool->getItem(rawurlencode($id));
return $item->isHit() ? $item->get() : false;
}
/**
* {@inheritdoc}
*
* @return bool
*/
protected function doContains($id)
{
return $this->pool->hasItem(rawurlencode($id));
}
/**
* {@inheritdoc}
*
* @return bool
*/
protected function doSave($id, $data, $lifeTime = 0)
{
$item = $this->pool->getItem(rawurlencode($id));
if (0 < $lifeTime) {
$item->expiresAfter($lifeTime);
}
return $this->pool->save($item->set($data));
}
/**
* {@inheritdoc}
*
* @return bool
*/
protected function doDelete($id)
{
return $this->pool->deleteItem(rawurlencode($id));
}
/**
* {@inheritdoc}
*
* @return bool
*/
protected function doFlush()
{
return $this->pool->clear();
}
/**
* {@inheritdoc}
*
* @return array|null
*/
protected function doGetStats()
{
return null;
}
}

View File

@@ -194,12 +194,12 @@ class Assets extends PropertyObject
}
$params = array_merge([$location], $params);
call_user_func_array([$this, 'add'], $params);
call_user_func_array($this->add(...), $params);
}
} elseif (isset($this->collections[$asset])) {
array_shift($args);
$args = array_merge([$this->collections[$asset]], $args);
call_user_func_array([$this, 'add'], $args);
call_user_func_array($this->add(...), $args);
} else {
// Get extension
$path = parse_url($asset, PHP_URL_PATH);
@@ -209,11 +209,11 @@ class Assets extends PropertyObject
if ($extension !== '') {
$extension = strtolower($extension);
if ($extension === 'css') {
call_user_func_array([$this, 'addCss'], $args);
call_user_func_array($this->addCss(...), $args);
} elseif ($extension === 'js') {
call_user_func_array([$this, 'addJs'], $args);
call_user_func_array($this->addJs(...), $args);
} elseif ($extension === 'mjs') {
call_user_func_array([$this, 'addJsModule'], $args);
call_user_func_array($this->addJsModule(...), $args);
}
}
}
@@ -261,7 +261,7 @@ class Assets extends PropertyObject
$default = 'before';
}
$options['position'] = $options['position'] ?? $default;
$options['position'] ??= $default;
}
unset($options['pipeline']);
@@ -432,9 +432,7 @@ class Assets extends PropertyObject
*/
protected function sortAssets($assets)
{
uasort($assets, static function ($a, $b) {
return $b['priority'] <=> $a['priority'] ?: $a['order'] <=> $b['order'];
});
uasort($assets, static fn($a, $b) => $b['priority'] <=> $a['priority'] ?: $a['order'] <=> $b['order']);
return $assets;
}
@@ -577,18 +575,11 @@ class Assets extends PropertyObject
*/
protected function getBaseType($type)
{
switch ($type) {
case $this::JS_TYPE:
case $this::INLINE_JS_TYPE:
$base_type = $this::JS;
break;
case $this::JS_MODULE_TYPE:
case $this::INLINE_JS_MODULE_TYPE:
$base_type = $this::JS_MODULE;
break;
default:
$base_type = $this::CSS;
}
$base_type = match ($type) {
$this::JS_TYPE, $this::INLINE_JS_TYPE => $this::JS,
$this::JS_MODULE_TYPE, $this::INLINE_JS_MODULE_TYPE => $this::JS_MODULE,
default => $this::CSS,
};
return $base_type;
}

View File

@@ -114,7 +114,7 @@ abstract class BaseAsset extends PropertyObject
// Do some special stuff for CSS/JS (not inline)
if (!Utils::startsWith($this->getType(), 'inline')) {
$this->base_url = rtrim($uri->rootUrl($config->get('system.absolute_urls')), '/') . '/';
$this->base_url = rtrim((string) $uri->rootUrl($config->get('system.absolute_urls')), '/') . '/';
$this->remote = static::isRemoteLink($asset);
// Move this to render?

View File

@@ -192,15 +192,15 @@ class BlockAssets
{
$grav = Grav::instance();
$base = rtrim($grav['base_url'], '/') ?: '/';
$base = rtrim((string) $grav['base_url'], '/') ?: '/';
if (strpos($url, $base) === 0) {
if (str_starts_with($url, $base)) {
if ($pipeline) {
// Remove file timestamp if CSS pipeline has been enabled.
$url = preg_replace('|[?#].*|', '', $url);
}
return substr($url, strlen($base) - 1);
return substr((string) $url, strlen($base) - 1);
}
return $url;
}

View File

@@ -283,7 +283,7 @@ class Pipeline extends PropertyObject
} else {
return str_replace($matches[2], $new_url, $matches[0]);
}
}, $file);
}, (string) $file);
return $file;
}

View File

@@ -55,7 +55,7 @@ trait AssetUtilsTrait
return false;
}
return (0 === strpos($link, 'http://') || 0 === strpos($link, 'https://') || 0 === strpos($link, '//'));
return (str_starts_with($link, 'http://') || str_starts_with($link, 'https://') || str_starts_with($link, '//'));
}
/**
@@ -76,18 +76,18 @@ trait AssetUtilsTrait
if (static::isRemoteLink($link)) {
$local = false;
if (0 === strpos($link, '//')) {
if (str_starts_with((string) $link, '//')) {
$link = 'http:' . $link;
}
$relative_dir = dirname($relative_path);
$relative_dir = dirname((string) $relative_path);
} else {
// Fix to remove relative dir if grav is in one
if (($this->base_url !== '/') && Utils::startsWith($relative_path, $this->base_url)) {
$base_url = '#' . preg_quote($this->base_url, '#') . '#';
$relative_path = ltrim(preg_replace($base_url, '/', $link, 1), '/');
$relative_path = ltrim((string) preg_replace($base_url, '/', (string) $link, 1), '/');
}
$relative_dir = dirname($relative_path);
$relative_dir = dirname((string) $relative_path);
$link = GRAV_ROOT . '/' . $relative_path;
}
@@ -101,7 +101,7 @@ trait AssetUtilsTrait
// Double check last character being
if ($type === self::JS_ASSET || $type === self::JS_MODULE_ASSET) {
$file = rtrim($file, ' ;') . ';';
$file = rtrim((string) $file, ' ;') . ';';
}
// If this is CSS + the file is local + rewrite enabled
@@ -113,7 +113,7 @@ trait AssetUtilsTrait
$file = $this->jsRewrite($file, $relative_dir, $local);
}
$file = rtrim($file) . PHP_EOL;
$file = rtrim((string) $file) . PHP_EOL;
$buffer .= $file;
}
@@ -170,9 +170,9 @@ trait AssetUtilsTrait
}
if (in_array($key, $no_key, true)) {
$element = htmlentities($value, ENT_QUOTES, 'UTF-8', false);
$element = htmlentities((string) $value, ENT_QUOTES, 'UTF-8', false);
} else {
$element = $key . '="' . htmlentities($value, ENT_QUOTES, 'UTF-8', false) . '"';
$element = $key . '="' . htmlentities((string) $value, ENT_QUOTES, 'UTF-8', false) . '"';
}
$html .= ' ' . $element;
@@ -191,7 +191,7 @@ trait AssetUtilsTrait
{
$querystring = '';
$asset = $asset ?? $this->asset;
$asset ??= $this->asset;
$attributes = $this->attributes;
if (!empty($this->query)) {

View File

@@ -113,7 +113,7 @@ trait LegacyAssetsTrait
*/
public function addAsyncJs($asset, $priority = 10, $pipeline = true, $group = 'head')
{
user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use dynamic method with [\'loading\' => \'async\']', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use dynamic method with [\'loading\' => \'async\']', E_USER_DEPRECATED);
return $this->addJs($asset, $priority, $pipeline, 'async', $group);
}
@@ -130,7 +130,7 @@ trait LegacyAssetsTrait
*/
public function addDeferJs($asset, $priority = 10, $pipeline = true, $group = 'head')
{
user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use dynamic method with [\'loading\' => \'defer\']', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use dynamic method with [\'loading\' => \'defer\']', E_USER_DEPRECATED);
return $this->addJs($asset, $priority, $pipeline, 'defer', $group);
}

View File

@@ -338,7 +338,7 @@ trait TestingAssetsTrait
$directory,
FilesystemIterator::SKIP_DOTS
)), $pattern);
$offset = strlen($ltrim);
$offset = strlen((string) $ltrim);
$files = [];
foreach ($iterator as $file) {

View File

@@ -54,7 +54,7 @@ class Backups
/** @var EventDispatcher $dispatcher */
$dispatcher = $grav['events'];
$dispatcher->addListener('onSchedulerInitialized', [$this, 'onSchedulerInitialized']);
$dispatcher->addListener('onSchedulerInitialized', $this->onSchedulerInitialized(...));
$grav->fireEvent('onBackupsInitialized', new Event(['backups' => $this]));
}
@@ -106,7 +106,7 @@ class Backups
{
$param_sep = Grav::instance()['config']->get('system.param_sep', ':');
$download = urlencode(base64_encode(Utils::basename($backup)));
$url = rtrim(Grav::instance()['uri']->rootUrl(true), '/') . '/' . trim(
$url = rtrim((string) Grav::instance()['uri']->rootUrl(true), '/') . '/' . trim(
$base_url,
'/'
) . '/task' . $param_sep . 'backup/download' . $param_sep . $download . '/admin-nonce' . $param_sep . Utils::getNonce('admin-form');
@@ -158,7 +158,7 @@ class Backups
static::$backups = [];
$grav = Grav::instance();
$backups_itr = new GlobIterator(static::$backup_dir . '/*.zip', FilesystemIterator::KEY_AS_FILENAME);
$backups_itr = new GlobIterator(static::$backup_dir . '/*.zip', FilesystemIterator::KEY_AS_FILENAME | \FilesystemIterator::SKIP_DOTS);
$inflector = $grav['inflector'];
$long_date_format = DATE_RFC2822;
@@ -194,7 +194,7 @@ class Backups
* @param callable|null $status
* @return string|null
*/
public static function backup($id = 0, callable $status = null)
public static function backup($id = 0, ?callable $status = null)
{
$grav = Grav::instance();
@@ -210,7 +210,7 @@ class Backups
$name = $grav['inflector']->underscorize($backup->name);
$date = date(static::BACKUP_DATE_FORMAT, time());
$filename = trim($name, '_') . '--' . $date . '.zip';
$filename = trim((string) $name, '_') . '--' . $date . '.zip';
$destination = static::$backup_dir . DS . $filename;
$max_execution_time = ini_set('max_execution_time', '600');
$backup_root = $backup->root;

View File

@@ -27,7 +27,7 @@ class Browser
{
try {
$this->useragent = parse_user_agent();
} catch (InvalidArgumentException $e) {
} catch (InvalidArgumentException) {
$this->useragent = parse_user_agent("Mozilla/5.0 (compatible; Unknown;)");
}
}

View File

@@ -10,7 +10,8 @@
namespace Grav\Common;
use DirectoryIterator;
use \Doctrine\Common\Cache as DoctrineCache;
use Doctrine\Common\Cache\CacheProvider;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Exception;
use Grav\Common\Config\Config;
use Grav\Common\Filesystem\Folder;
@@ -18,6 +19,12 @@ use Grav\Common\Scheduler\Scheduler;
use LogicException;
use Psr\SimpleCache\CacheInterface;
use RocketTheme\Toolbox\Event\Event;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Adapter\ApcuAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\MemcachedAdapter;
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Cache\Psr16Cache;
use Symfony\Component\EventDispatcher\EventDispatcher;
use function dirname;
use function extension_loaded;
@@ -27,12 +34,11 @@ use function is_array;
/**
* The GravCache object is used throughout Grav to store and retrieve cached data.
* It uses DoctrineCache library and supports a variety of caching mechanisms. Those include:
* It uses Symfony library (adding backward compatibility to Doctrine Cache) and supports a variety of caching mechanisms. Those include:
*
* APCu
* RedisCache
* MemCache
* MemCacheD
* MemCached
* FileSystem
*/
class Cache extends Getters
@@ -49,7 +55,10 @@ class Cache extends Getters
/** @var Config $config */
protected $config;
/** @var DoctrineCache\CacheProvider */
/** @var AdapterInterface */
protected $adapter;
/** @var CacheProvider */
protected $driver;
/** @var CacheInterface */
@@ -70,6 +79,7 @@ class Cache extends Getters
protected static $standard_remove = [
'cache://twig/',
'cache://doctrine/',
'cache://grav/',
'cache://compiled/',
'cache://clockwork/',
'cache://validated-',
@@ -80,6 +90,7 @@ class Cache extends Getters
protected static $standard_remove_no_images = [
'cache://twig/',
'cache://doctrine/',
'cache://grav/',
'cache://compiled/',
'cache://clockwork/',
'cache://validated-',
@@ -142,14 +153,14 @@ class Cache extends Getters
// Cache key allows us to invalidate all cache on configuration changes.
$this->key = ($prefix ?: 'g') . '-' . $uniqueness;
$this->cache_dir = $grav['locator']->findResource('cache://doctrine/' . $uniqueness, true, true);
$this->cache_dir = $grav['locator']->findResource('cache://grav/' . $uniqueness, true, true);
$this->driver_setting = $this->config->get('system.cache.driver');
$this->driver = $this->getCacheDriver();
$this->driver->setNamespace($this->key);
$this->adapter = $this->getCacheAdapter();
$this->driver = $this->getCacheDriver($this->adapter);
/** @var EventDispatcher $dispatcher */
$dispatcher = Grav::instance()['events'];
$dispatcher->addListener('onSchedulerInitialized', [$this, 'onSchedulerInitialized']);
$dispatcher->addListener('onSchedulerInitialized', $this->onSchedulerInitialized(...));
}
/**
@@ -158,12 +169,7 @@ class Cache extends Getters
public function getSimpleCache()
{
if (null === $this->simpleCache) {
$cache = new \Grav\Framework\Cache\Adapter\DoctrineCache($this->driver, '', $this->getLifetime());
// Disable cache key validation.
$cache->setValidation(false);
$this->simpleCache = $cache;
$this->simpleCache = new Psr16Cache($this->adapter);
}
return $this->simpleCache;
@@ -280,53 +286,42 @@ class Cache extends Getters
* If there is no config option for $driver in the config, or it's set to 'auto', it will
* pick the best option based on which cache extensions are installed.
*
* @return DoctrineCache\CacheProvider The cache driver to use
* @param string|null $namespace
* @param int|null $defaultLifetime
* @return AdapterInterface The cache driver to use
* @throws \RedisException
* @throws \Symfony\Component\Cache\Exception\CacheException
*/
public function getCacheDriver()
public function getCacheAdapter(?string $namespace = null, ?int $defaultLifetime = null): AdapterInterface
{
$setting = $this->driver_setting;
$setting = $this->driver_setting ?? 'auto';
$driver_name = 'file';
if (in_array($setting, ['apc', 'xcache', 'wincache', 'memcache'], true)) {
throw new LogicException(sprintf('Cache driver for %s has been removed, use auto, file, apcu or memcached instead!', $setting));
}
// CLI compatibility requires a non-volatile cache driver
if ($this->config->get('system.cache.cli_compatibility') && (
$setting === 'auto' || $this->isVolatileDriver($setting))) {
if ($this->config->get('system.cache.cli_compatibility') && ($setting === 'auto' || $this->isVolatileDriver($setting))) {
$setting = $driver_name;
}
if (!$setting || $setting === 'auto') {
if ($setting === 'auto' || $this->isVolatileDriver($setting)) {
if (extension_loaded('apcu')) {
$driver_name = 'apcu';
} elseif (extension_loaded('wincache')) {
$driver_name = 'wincache';
}
} else {
$driver_name = $setting;
}
$this->driver_name = $driver_name;
$namespace ??= $this->key;
$defaultLifetime ??= 0;
switch ($driver_name) {
case 'apc':
case 'apcu':
$driver = new DoctrineCache\ApcuCache();
break;
case 'wincache':
$driver = new DoctrineCache\WinCacheCache();
break;
case 'memcache':
if (extension_loaded('memcache')) {
$memcache = new \Memcache();
$memcache->connect(
$this->config->get('system.cache.memcache.server', 'localhost'),
$this->config->get('system.cache.memcache.port', 11211)
);
$driver = new DoctrineCache\MemcacheCache();
$driver->setMemcache($memcache);
} else {
throw new LogicException('Memcache PHP extension has not been installed');
}
$adapter = new ApcuAdapter($namespace, $defaultLifetime);
break;
case 'memcached':
@@ -336,8 +331,7 @@ class Cache extends Getters
$this->config->get('system.cache.memcached.server', 'localhost'),
$this->config->get('system.cache.memcached.port', 11211)
);
$driver = new DoctrineCache\MemcachedCache();
$driver->setMemcached($memcached);
$adapter = new MemcachedAdapter($memcached, $namespace, $defaultLifetime);
} else {
throw new LogicException('Memcached PHP extension has not been installed');
}
@@ -369,19 +363,39 @@ class Cache extends Getters
throw new \RedisException('Could not select alternate Redis database ID');
}
$driver = new DoctrineCache\RedisCache();
$driver->setRedis($redis);
$adapter = new RedisAdapter($redis, $namespace, $defaultLifetime);
} else {
throw new LogicException('Redis PHP extension has not been installed');
}
break;
default:
$driver = new DoctrineCache\FilesystemCache($this->cache_dir);
$adapter = new FilesystemAdapter($namespace, $defaultLifetime, $this->cache_dir);
break;
}
return $driver;
return $adapter;
}
/**
* Automatically picks the cache mechanism to use. If you pick one manually it will use that
* If there is no config option for $driver in the config, or it's set to 'auto', it will
* pick the best option based on which cache extensions are installed.
*
* @return CacheProvider The cache driver to use
*/
public function getCacheDriver(?AdapterInterface $adapter = null)
{
if (null === $adapter) {
$adapter = $this->getCacheAdapter();
}
$cache = DoctrineProvider::wrap($adapter);
if (!$cache instanceof CacheProvider) {
throw new \RuntimeException('Internal error');
}
return $cache;
}
/**
@@ -523,8 +537,17 @@ class Cache extends Getters
// Delete entries in the doctrine cache if required
if (in_array($remove, ['all', 'standard'])) {
$cache = Grav::instance()['cache'];
$cache->driver->deleteAll();
try {
$grav = Grav::instance();
if ($grav->offsetExists('cache')) {
$cache = $grav['cache'];
if (isset($cache->driver)) {
$cache->driver->deleteAll();
}
}
} catch (\Throwable $e) {
$output[] = 'cache: ' . $e->getMessage();
}
}
// Clearing cache event to add paths to clear
@@ -669,7 +692,7 @@ class Cache extends Getters
*/
public function isVolatileDriver($setting)
{
return in_array($setting, ['apc', 'apcu', 'xcache', 'wincache'], true);
return $setting === 'apcu';
}
/**

View File

@@ -202,7 +202,7 @@ abstract class CompiledBase
$cache = include $filename;
if (!is_array($cache)
|| !isset($cache['checksum'], $cache['data'], $cache['@class'])
|| $cache['@class'] !== get_class($this)
|| $cache['@class'] !== static::class
) {
return false;
}
@@ -235,7 +235,7 @@ abstract class CompiledBase
// Attempt to lock the file for writing.
try {
$file->lock(false);
} catch (Exception $e) {
} catch (Exception) {
// Another process has locked the file; we will check this in a bit.
}
@@ -245,7 +245,7 @@ abstract class CompiledBase
}
$cache = [
'@class' => get_class($this),
'@class' => static::class,
'timestamp' => time(),
'checksum' => $this->checksum(),
'files' => $this->files,

View File

@@ -149,7 +149,7 @@ class Config extends Data
*/
public function getLanguages()
{
user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.5, use Grav::instance()[\'languages\'] instead', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '() is deprecated since Grav 1.5, use Grav::instance()[\'languages\'] instead', E_USER_DEPRECATED);
return Grav::instance()['languages'];
}

View File

@@ -178,9 +178,7 @@ class ConfigFileFinder
'filters' => [
'pre-key' => $this->base,
'key' => $pattern,
'value' => function (RecursiveDirectoryIterator $file) use ($path) {
return ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()];
}
'value' => fn(RecursiveDirectoryIterator $file) => ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()]
],
'key' => 'SubPathname'
];
@@ -254,9 +252,7 @@ class ConfigFileFinder
'filters' => [
'pre-key' => $this->base,
'key' => $pattern,
'value' => function (RecursiveDirectoryIterator $file) use ($path) {
return ["{$path}/{$file->getSubPathname()}" => $file->getMTime()];
}
'value' => fn(RecursiveDirectoryIterator $file) => ["{$path}/{$file->getSubPathname()}" => $file->getMTime()]
],
'key' => 'SubPathname'
];

View File

@@ -202,7 +202,7 @@ class Setup extends Data
$setupFile = defined('GRAV_SETUP_PATH') ? GRAV_SETUP_PATH : (getenv('GRAV_SETUP_PATH') ?: null);
if (null !== $setupFile) {
// Make sure that the custom setup file exists. Terminates the script if not.
if (!str_starts_with($setupFile, '/')) {
if (!str_starts_with((string) $setupFile, '/')) {
$setupFile = GRAV_WEBROOT . '/' . $setupFile;
}
if (!is_file($setupFile)) {

View File

@@ -142,7 +142,7 @@ class Blueprint extends BlueprintForm
{
foreach ($this->dynamic as $key => $data) {
// Locate field.
$path = explode('/', $key);
$path = explode('/', (string) $key);
$current = &$this->items;
foreach ($path as $field) {
@@ -168,7 +168,7 @@ class Blueprint extends BlueprintForm
// Set dynamic property.
foreach ($data as $property => $call) {
$action = $call['action'];
$method = 'dynamic' . ucfirst($action);
$method = 'dynamic' . ucfirst((string) $action);
$call['object'] = $this->object;
if (isset($this->handlers[$action])) {
@@ -434,7 +434,7 @@ class Blueprint extends BlueprintForm
$params = [];
}
[$o, $f] = explode('::', $function, 2);
[$o, $f] = explode('::', (string) $function, 2);
$data = null;
if (!$f) {
@@ -574,10 +574,9 @@ class Blueprint extends BlueprintForm
/**
* @param array $field
* @param string $property
* @param mixed $value
* @return void
*/
public static function addPropertyRecursive(array &$field, $property, $value)
public static function addPropertyRecursive(array &$field, $property, mixed $value)
{
if (is_array($value) && isset($field[$property]) && is_array($field[$property])) {
$field[$property] = array_merge_recursive($field[$property], $value);

View File

@@ -130,7 +130,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
foreach ($items as $key => $rules) {
$type = $rules['type'] ?? '';
$ignore = (bool) array_filter((array)($rules['validate']['ignore'] ?? [])) ?? false;
if (!str_starts_with($type, '_') && !str_contains($key, '*') && $ignore !== true) {
if (!str_starts_with((string) $type, '_') && !str_contains((string) $key, '*') && $ignore !== true) {
$list[$prefix . $key] = null;
}
}
@@ -215,7 +215,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
// If strings:
if (is_string($currentVal) && is_string($otherVal)) {
$isValid = (strlen($currentVal) && strlen($otherVal) && (str_contains($currentVal,
$otherVal) || strpos($otherVal, $currentVal) !== false));
$otherVal) || str_contains($otherVal, $currentVal)));
}
// If arrays:
if (is_array($currentVal) && is_array($otherVal)) {

View File

@@ -22,8 +22,6 @@ use function is_object;
*/
class Blueprints
{
/** @var array|string */
protected $search;
/** @var array */
protected $types;
/** @var array */
@@ -32,9 +30,8 @@ class Blueprints
/**
* @param string|array $search Search path.
*/
public function __construct($search = 'blueprints://')
public function __construct(protected $search = 'blueprints://')
{
$this->search = $search;
}
/**

View File

@@ -103,7 +103,7 @@ class Data implements DataInterface, ArrayAccess, \Countable, JsonSerializable,
* @return $this
* @throws RuntimeException
*/
public function join($name, $value, $separator = '.')
public function join($name, mixed $value, $separator = '.')
{
$old = $this->get($name, null, $separator);
if ($old !== null) {
@@ -145,7 +145,7 @@ class Data implements DataInterface, ArrayAccess, \Countable, JsonSerializable,
* @param string $separator Separator, defaults to '.'
* @return $this
*/
public function joinDefaults($name, $value, $separator = '.')
public function joinDefaults($name, mixed $value, $separator = '.')
{
if (is_object($value)) {
$value = (array) $value;
@@ -323,7 +323,7 @@ class Data implements DataInterface, ArrayAccess, \Countable, JsonSerializable,
* @param FileInterface|null $storage Optionally enter a new storage.
* @return FileInterface|null
*/
public function file(FileInterface $storage = null)
public function file(?FileInterface $storage = null)
{
if ($storage) {
$this->storage = $storage;

View File

@@ -28,7 +28,7 @@ interface DataInterface
* @param string $separator Separator, defaults to '.'
* @return mixed Value.
*/
public function value($name, $default = null, $separator = '.');
public function value($name, mixed $default = null, $separator = '.');
/**
* Merge external data.
@@ -80,5 +80,5 @@ interface DataInterface
* @param FileInterface|null $storage Optionally enter a new storage.
* @return FileInterface
*/
public function file(FileInterface $storage = null);
public function file(?FileInterface $storage = null);
}

View File

@@ -37,11 +37,10 @@ class Validation
/**
* Validate value against a blueprint field definition.
*
* @param mixed $value
* @param array $field
* @return array
*/
public static function validate($value, array $field)
public static function validate(mixed $value, array $field)
{
if (!isset($field['type'])) {
$field['type'] = 'text';
@@ -78,7 +77,7 @@ class Validation
$messages = [];
$success = method_exists(__CLASS__, $method) ? self::$method($value, $validate, $field) : true;
$success = method_exists(self::class, $method) ? self::$method($value, $validate, $field) : true;
if (!$success) {
$messages[$field['name']][] = $message;
}
@@ -87,7 +86,7 @@ class Validation
foreach ($validate as $rule => $params) {
$method = 'validate' . ucfirst(str_replace('-', '_', $rule));
if (method_exists(__CLASS__, $method)) {
if (method_exists(self::class, $method)) {
$success = self::$method($value, $params);
if (!$success) {
@@ -100,11 +99,10 @@ class Validation
}
/**
* @param mixed $value
* @param array $field
* @return array
*/
public static function checkSafety($value, array $field)
public static function checkSafety(mixed $value, array $field)
{
$messages = [];
@@ -117,7 +115,7 @@ class Validation
$options = [];
}
$name = ucfirst($field['label'] ?? $field['name'] ?? 'UNKNOWN');
$name = ucfirst((string) ($field['label'] ?? $field['name'] ?? 'UNKNOWN'));
/** @var UserInterface $user */
$user = Grav::instance()['user'] ?? null;
@@ -164,7 +162,7 @@ class Validation
* @param UserInterface|null $user
* @return bool
*/
public static function authorize($action, UserInterface $user = null)
public static function authorize($action, ?UserInterface $user = null)
{
if (!$user) {
return false;
@@ -188,11 +186,10 @@ class Validation
/**
* Filter value against a blueprint field definition.
*
* @param mixed $value
* @param array $field
* @return mixed Filtered value.
*/
public static function filter($value, array $field)
public static function filter(mixed $value, array $field)
{
$validate = (array)($field['filter'] ?? $field['validate'] ?? null);
@@ -213,7 +210,7 @@ class Validation
$method = 'filterYaml';
}
if (!method_exists(__CLASS__, $method)) {
if (!method_exists(self::class, $method)) {
$method = isset($field['array']) && $field['array'] === true ? 'filterArray' : 'filterText';
}
@@ -228,7 +225,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeText($value, array $params, array $field)
public static function typeText(mixed $value, array $params, array $field)
{
if (!is_string($value) && !is_numeric($value)) {
return false;
@@ -241,7 +238,7 @@ class Validation
}
$value = preg_replace("/\r\n|\r/um", "\n", $value);
$len = mb_strlen($value);
$len = mb_strlen((string) $value);
$min = (int)($params['min'] ?? 0);
if ($min && $len < $min) {
@@ -260,7 +257,7 @@ class Validation
return false;
}
if (!$multiline && preg_match('/\R/um', $value)) {
if (!$multiline && preg_match('/\R/um', (string) $value)) {
return false;
}
@@ -268,12 +265,11 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return string
*/
protected static function filterText($value, array $params, array $field)
protected static function filterText(mixed $value, array $params, array $field)
{
if (!is_string($value) && !is_numeric($value)) {
return '';
@@ -289,12 +285,11 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return string|null
*/
protected static function filterCheckbox($value, array $params, array $field)
protected static function filterCheckbox(mixed $value, array $params, array $field)
{
$value = (string)$value;
$field_value = (string)($field['value'] ?? '1');
@@ -303,23 +298,21 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return array|array[]|false|string[]
*/
protected static function filterCommaList($value, array $params, array $field)
protected static function filterCommaList(mixed $value, array $params, array $field)
{
return is_array($value) ? $value : preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
return is_array($value) ? $value : preg_split('/\s*,\s*/', (string) $value, -1, PREG_SPLIT_NO_EMPTY);
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return bool
*/
public static function typeCommaList($value, array $params, array $field)
public static function typeCommaList(mixed $value, array $params, array $field)
{
if (!isset($params['max'])) {
$params['max'] = 2048;
@@ -329,34 +322,31 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return array|array[]|false|string[]
*/
protected static function filterLines($value, array $params, array $field)
protected static function filterLines(mixed $value, array $params, array $field)
{
return is_array($value) ? $value : preg_split('/\s*[\r\n]+\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
return is_array($value) ? $value : preg_split('/\s*[\r\n]+\s*/', (string) $value, -1, PREG_SPLIT_NO_EMPTY);
}
/**
* @param mixed $value
* @param array $params
* @return string
*/
protected static function filterLower($value, array $params)
protected static function filterLower(mixed $value, array $params)
{
return mb_strtolower($value);
return mb_strtolower((string) $value);
}
/**
* @param mixed $value
* @param array $params
* @return string
*/
protected static function filterUpper($value, array $params)
protected static function filterUpper(mixed $value, array $params)
{
return mb_strtoupper($value);
return mb_strtoupper((string) $value);
}
@@ -368,7 +358,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeTextarea($value, array $params, array $field)
public static function typeTextarea(mixed $value, array $params, array $field)
{
if (!isset($params['multiline'])) {
$params['multiline'] = true;
@@ -385,7 +375,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typePassword($value, array $params, array $field)
public static function typePassword(mixed $value, array $params, array $field)
{
if (!isset($params['max'])) {
$params['max'] = 256;
@@ -402,7 +392,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeHidden($value, array $params, array $field)
public static function typeHidden(mixed $value, array $params, array $field)
{
return self::typeText($value, $params, $field);
}
@@ -415,7 +405,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeCheckboxes($value, array $params, array $field)
public static function typeCheckboxes(mixed $value, array $params, array $field)
{
// Set multiple: true so checkboxes can easily use min/max counts to control number of options required
$field['multiple'] = true;
@@ -424,12 +414,11 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return array|null
*/
protected static function filterCheckboxes($value, array $params, array $field)
protected static function filterCheckboxes(mixed $value, array $params, array $field)
{
return self::filterArray($value, $params, $field);
}
@@ -442,7 +431,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeCheckbox($value, array $params, array $field)
public static function typeCheckbox(mixed $value, array $params, array $field)
{
$value = (string)$value;
$field_value = (string)($field['value'] ?? '1');
@@ -458,7 +447,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeRadio($value, array $params, array $field)
public static function typeRadio(mixed $value, array $params, array $field)
{
return self::typeArray((array) $value, $params, $field);
}
@@ -471,7 +460,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeToggle($value, array $params, array $field)
public static function typeToggle(mixed $value, array $params, array $field)
{
if (is_bool($value)) {
$value = (int)$value;
@@ -488,18 +477,17 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeFile($value, array $params, array $field)
public static function typeFile(mixed $value, array $params, array $field)
{
return self::typeArray((array)$value, $params, $field);
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return array
*/
protected static function filterFile($value, array $params, array $field)
protected static function filterFile(mixed $value, array $params, array $field)
{
return (array)$value;
}
@@ -512,7 +500,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeSelect($value, array $params, array $field)
public static function typeSelect(mixed $value, array $params, array $field)
{
return self::typeArray((array) $value, $params, $field);
}
@@ -525,7 +513,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeNumber($value, array $params, array $field)
public static function typeNumber(mixed $value, array $params, array $field)
{
if (!is_numeric($value)) {
return false;
@@ -560,23 +548,21 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return float|int
*/
protected static function filterNumber($value, array $params, array $field)
protected static function filterNumber(mixed $value, array $params, array $field)
{
return (string)(int)$value !== (string)(float)$value ? (float)$value : (int)$value;
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return string
*/
protected static function filterDateTime($value, array $params, array $field)
protected static function filterDateTime(mixed $value, array $params, array $field)
{
$format = Grav::instance()['config']->get('system.pages.dateformat.default');
if ($format) {
@@ -594,18 +580,17 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeRange($value, array $params, array $field)
public static function typeRange(mixed $value, array $params, array $field)
{
return self::typeNumber($value, $params, $field);
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return float|int
*/
protected static function filterRange($value, array $params, array $field)
protected static function filterRange(mixed $value, array $params, array $field)
{
return self::filterNumber($value, $params, $field);
}
@@ -618,9 +603,9 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeColor($value, array $params, array $field)
public static function typeColor(mixed $value, array $params, array $field)
{
return (bool)preg_match('/^\#[0-9a-fA-F]{3}[0-9a-fA-F]{3}?$/u', $value);
return (bool)preg_match('/^\#[0-9a-fA-F]{3}[0-9a-fA-F]{3}?$/u', (string) $value);
}
/**
@@ -631,7 +616,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeEmail($value, array $params, array $field)
public static function typeEmail(mixed $value, array $params, array $field)
{
if (empty($value)) {
return false;
@@ -641,10 +626,10 @@ class Validation
$params['max'] = 320;
}
$values = !is_array($value) ? explode(',', preg_replace('/\s+/', '', $value)) : $value;
$values = !is_array($value) ? explode(',', (string) preg_replace('/\s+/', '', (string) $value)) : $value;
foreach ($values as $val) {
if (!(self::typeText($val, $params, $field) && strpos($val, '@', 1))) {
if (!(self::typeText($val, $params, $field) && strpos((string) $val, '@', 1))) {
return false;
}
}
@@ -660,7 +645,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeUrl($value, array $params, array $field)
public static function typeUrl(mixed $value, array $params, array $field)
{
if (!isset($params['max'])) {
$params['max'] = 2048;
@@ -677,7 +662,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeDatetime($value, array $params, array $field)
public static function typeDatetime(mixed $value, array $params, array $field)
{
if ($value instanceof DateTime) {
return true;
@@ -702,7 +687,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeDatetimeLocal($value, array $params, array $field)
public static function typeDatetimeLocal(mixed $value, array $params, array $field)
{
return self::typeDatetime($value, $params, $field);
}
@@ -715,7 +700,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeDate($value, array $params, array $field)
public static function typeDate(mixed $value, array $params, array $field)
{
if (!isset($params['format'])) {
$params['format'] = 'Y-m-d';
@@ -732,7 +717,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeTime($value, array $params, array $field)
public static function typeTime(mixed $value, array $params, array $field)
{
if (!isset($params['format'])) {
$params['format'] = 'H:i';
@@ -749,7 +734,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeMonth($value, array $params, array $field)
public static function typeMonth(mixed $value, array $params, array $field)
{
if (!isset($params['format'])) {
$params['format'] = 'Y-m';
@@ -766,9 +751,9 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeWeek($value, array $params, array $field)
public static function typeWeek(mixed $value, array $params, array $field)
{
if (!isset($params['format']) && !preg_match('/^\d{4}-W\d{2}$/u', $value)) {
if (!isset($params['format']) && !preg_match('/^\d{4}-W\d{2}$/u', (string) $value)) {
return false;
}
@@ -783,7 +768,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeArray($value, array $params, array $field)
public static function typeArray(mixed $value, array $params, array $field)
{
if (!is_array($value)) {
return false;
@@ -831,12 +816,11 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return array|null
*/
protected static function filterFlatten_array($value, $params, $field)
protected static function filterFlatten_array(mixed $value, $params, $field)
{
$value = static::filterArray($value, $params, $field);
@@ -844,12 +828,11 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return array|null
*/
protected static function filterArray($value, $params, $field)
protected static function filterArray(mixed $value, $params, $field)
{
$values = (array) $value;
$options = isset($field['options']) ? array_keys($field['options']) : [];
@@ -873,7 +856,7 @@ class Validation
$val = implode(',', $val);
$values[$key] = array_map('trim', explode(',', $val));
} else {
$values[$key] = trim($val);
$values[$key] = trim((string) $val);
}
}
}
@@ -897,16 +880,11 @@ class Validation
{
foreach ($values as $key => &$val) {
if ($params['key_type']) {
switch ($params['key_type']) {
case 'int':
$result = is_int($key);
break;
case 'string':
$result = is_string($key);
break;
default:
$result = false;
}
$result = match ($params['key_type']) {
'int' => is_int($key),
'string' => is_string($key),
default => false,
};
if (!$result) {
unset($values[$key]);
}
@@ -939,7 +917,7 @@ class Validation
$val = (string)$val;
break;
case 'trim':
$val = trim($val);
$val = trim((string) $val);
break;
}
}
@@ -954,12 +932,11 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return bool
*/
public static function typeList($value, array $params, array $field)
public static function typeList(mixed $value, array $params, array $field)
{
if (!is_array($value)) {
return false;
@@ -968,7 +945,7 @@ class Validation
if (isset($field['fields'])) {
foreach ($value as $key => $item) {
foreach ($field['fields'] as $subKey => $subField) {
$subKey = trim($subKey, '.');
$subKey = trim((string) $subKey, '.');
$subValue = $item[$subKey] ?? null;
self::validate($subValue, $subField);
}
@@ -979,22 +956,20 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return array
*/
protected static function filterList($value, array $params, array $field)
protected static function filterList(mixed $value, array $params, array $field)
{
return (array) $value;
}
/**
* @param mixed $value
* @param array $params
* @return array
*/
public static function filterYaml($value, $params)
public static function filterYaml(mixed $value, $params)
{
if (!is_string($value)) {
return $value;
@@ -1011,18 +986,17 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeIgnore($value, array $params, array $field)
public static function typeIgnore(mixed $value, array $params, array $field)
{
return true;
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return mixed
*/
public static function filterIgnore($value, array $params, array $field)
public static function filterIgnore(mixed $value, array $params, array $field)
{
return $value;
}
@@ -1035,30 +1009,27 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeUnset($value, array $params, array $field)
public static function typeUnset(mixed $value, array $params, array $field)
{
return true;
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return null
*/
public static function filterUnset($value, array $params, array $field)
public static function filterUnset(mixed $value, array $params, array $field)
{
return null;
}
// HTML5 attributes (min, max and range are handled inside the types)
/**
* @param mixed $value
* @param bool $params
* @return bool
*/
public static function validateRequired($value, $params)
public static function validateRequired(mixed $value, $params)
{
if (is_scalar($value)) {
return (bool) $params !== true || $value !== '';
@@ -1068,105 +1039,85 @@ class Validation
}
/**
* @param mixed $value
* @param string $params
* @return bool
*/
public static function validatePattern($value, $params)
public static function validatePattern(mixed $value, $params)
{
return (bool) preg_match("`^{$params}$`u", $value);
return (bool) preg_match("`^{$params}$`u", (string) $value);
}
// Internal types
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateAlpha($value, $params)
public static function validateAlpha(mixed $value, mixed $params)
{
return ctype_alpha($value);
return ctype_alpha((string) $value);
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateAlnum($value, $params)
public static function validateAlnum(mixed $value, mixed $params)
{
return ctype_alnum($value);
return ctype_alnum((string) $value);
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function typeBool($value, $params)
public static function typeBool(mixed $value, mixed $params)
{
return is_bool($value) || $value == 1 || $value == 0;
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateBool($value, $params)
public static function validateBool(mixed $value, mixed $params)
{
return is_bool($value) || $value == 1 || $value == 0;
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
protected static function filterBool($value, $params)
protected static function filterBool(mixed $value, mixed $params)
{
return (bool) $value;
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateDigit($value, $params)
public static function validateDigit(mixed $value, mixed $params)
{
return ctype_digit($value);
return ctype_digit((string) $value);
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateFloat($value, $params)
public static function validateFloat(mixed $value, mixed $params)
{
return is_float(filter_var($value, FILTER_VALIDATE_FLOAT));
}
/**
* @param mixed $value
* @param mixed $params
* @return float
*/
protected static function filterFloat($value, $params)
protected static function filterFloat(mixed $value, mixed $params)
{
return (float) $value;
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateHex($value, $params)
public static function validateHex(mixed $value, mixed $params)
{
return ctype_xdigit($value);
return ctype_xdigit((string) $value);
}
/**
@@ -1177,7 +1128,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeInt($value, array $params, array $field)
public static function typeInt(mixed $value, array $params, array $field)
{
$params['step'] = max(1, (int)($params['step'] ?? 0));
@@ -1185,54 +1136,42 @@ class Validation
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateInt($value, $params)
public static function validateInt(mixed $value, mixed $params)
{
return is_numeric($value) && (int)$value == $value;
}
/**
* @param mixed $value
* @param mixed $params
* @return int
*/
protected static function filterInt($value, $params)
protected static function filterInt(mixed $value, mixed $params)
{
return (int)$value;
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateArray($value, $params)
public static function validateArray(mixed $value, mixed $params)
{
return is_array($value) || ($value instanceof ArrayAccess && $value instanceof Traversable && $value instanceof Countable);
}
/**
* @param mixed $value
* @param mixed $params
* @return array
*/
public static function filterItem_List($value, $params)
public static function filterItem_List(mixed $value, mixed $params)
{
return array_values(array_filter($value, static function ($v) {
return !empty($v);
}));
return array_values(array_filter($value, static fn($v) => !empty($v)));
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateJson($value, $params)
public static function validateJson(mixed $value, mixed $params)
{
return (bool) (@json_decode($value));
return (bool) (@json_decode((string) $value));
}
}

View File

@@ -37,7 +37,7 @@ class ValidationException extends RuntimeException implements JsonSerializable
foreach ($messages as $list) {
$list = array_unique($list);
foreach ($list as $message) {
$this->message .= '<br/>' . htmlspecialchars($message, ENT_QUOTES | ENT_HTML5, 'UTF-8');
$this->message .= '<br/>' . htmlspecialchars((string) $message, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}
}
@@ -49,7 +49,7 @@ class ValidationException extends RuntimeException implements JsonSerializable
$first = reset($this->messages);
$message = reset($first);
$this->message = $escape ? htmlspecialchars($message, ENT_QUOTES | ENT_HTML5, 'UTF-8') : $message;
$this->message = $escape ? htmlspecialchars((string) $message, ENT_QUOTES | ENT_HTML5, 'UTF-8') : $message;
}
/**

View File

@@ -328,9 +328,7 @@ class Debugger
return new Response(404, $headers, json_encode($response));
}
$data = is_array($data) ? array_map(static function ($item) {
return $item->toArray();
}, $data) : $data->toArray();
$data = is_array($data) ? array_map(static fn($item) => $item->toArray(), $data) : $data->toArray();
return new Response(200, $headers, json_encode($data));
}
@@ -544,7 +542,7 @@ class Debugger
* @param string|null $message
* @return mixed
*/
public function profile(callable $callable, string $message = null)
public function profile(callable $callable, ?string $message = null)
{
$this->startProfiling();
$response = $callable();
@@ -585,7 +583,7 @@ class Debugger
* @param string|null $message
* @return array|null
*/
public function stopProfiling(string $message = null): ?array
public function stopProfiling(?string $message = null): ?array
{
$timings = null;
if ($this->enabled && extension_loaded('tideways_xhprof')) {
@@ -619,17 +617,13 @@ class Debugger
protected function buildProfilerTimings(array $timings): array
{
// Filter method calls which take almost no time.
$timings = array_filter($timings, function ($value) {
return $value['wt'] > 50;
});
$timings = array_filter($timings, fn($value) => $value['wt'] > 50);
uasort($timings, function (array $a, array $b) {
return $b['wt'] <=> $a['wt'];
});
uasort($timings, fn(array $a, array $b) => $b['wt'] <=> $a['wt']);
$table = [];
foreach ($timings as $key => $timing) {
$parts = explode('==>', $key);
$parts = explode('==>', (string) $key);
$method = $this->parseProfilerCall(array_pop($parts));
$context = $this->parseProfilerCall(array_pop($parts));
@@ -639,7 +633,7 @@ class Debugger
}
// Do not profile library calls.
if (strpos($context, 'Grav\\') !== 0) {
if (!str_starts_with((string) $context, 'Grav\\')) {
continue;
}
@@ -721,12 +715,11 @@ class Debugger
/**
* Dump variables into the Messages tab of the Debug Bar
*
* @param mixed $message
* @param string $label
* @param mixed|bool $isString
* @return $this
*/
public function addMessage($message, $label = 'info', $isString = true)
public function addMessage(mixed $message, $label = 'info', $isString = true)
{
if ($this->enabled) {
if ($this->censored) {
@@ -776,10 +769,10 @@ class Debugger
* @param float|null $time
* @return $this
*/
public function addEvent(string $name, $event, EventDispatcherInterface $dispatcher, float $time = null)
public function addEvent(string $name, $event, EventDispatcherInterface $dispatcher, ?float $time = null)
{
if ($this->enabled && $this->clockwork) {
$time = $time ?? microtime(true);
$time ??= microtime(true);
$duration = (microtime(true) - $time) * 1000;
$data = null;
@@ -829,7 +822,7 @@ class Debugger
public function setErrorHandler()
{
$this->errorHandler = set_error_handler(
[$this, 'deprecatedErrorHandler']
$this->deprecatedErrorHandler(...)
);
}
@@ -858,7 +851,7 @@ class Debugger
$scope = 'unknown';
if (stripos($errstr, 'grav') !== false) {
$scope = 'grav';
} elseif (strpos($errfile, '/twig/') !== false) {
} elseif (str_contains($errfile, '/twig/')) {
$scope = 'twig';
// TODO: remove when upgrading to Twig 2+
if (str_contains($errstr, '#[\ReturnTypeWillChange]') || str_contains($errstr, 'Passing null to parameter')) {
@@ -866,7 +859,7 @@ class Debugger
}
} elseif (stripos($errfile, '/yaml/') !== false) {
$scope = 'yaml';
} elseif (strpos($errfile, '/vendor/') !== false) {
} elseif (str_contains($errfile, '/vendor/')) {
$scope = 'vendor';
}
@@ -912,7 +905,7 @@ class Debugger
} elseif (is_scalar($arg)) {
$arg = $arg;
} elseif (is_object($arg)) {
$arg = get_class($arg) . ' $object';
$arg = $arg::class . ' $object';
} elseif (is_array($arg)) {
$arg = '$array';
} else {
@@ -931,14 +924,13 @@ class Debugger
if ($object instanceof TemplateWrapper) {
$reflection = new ReflectionObject($object);
$property = $reflection->getProperty('template');
$property->setAccessible(true);
$object = $property->getValue($object);
}
if ($object instanceof Template) {
$file = $current['file'] ?? null;
if (preg_match('`(Template.php|TemplateWrapper.php)$`', $file)) {
if (preg_match('`(Template.php|TemplateWrapper.php)$`', (string) $file)) {
$current = null;
continue;
}
@@ -998,7 +990,7 @@ class Debugger
if (!isset($current['file'])) {
continue;
}
if (strpos($current['file'], '/vendor/') !== false) {
if (str_contains($current['file'], '/vendor/')) {
$cut = $i + 1;
continue;
}
@@ -1073,7 +1065,7 @@ class Debugger
/** @var array $deprecated */
foreach ($this->deprecations as $deprecated) {
list($message, $scope) = $this->getDepracatedMessage($deprecated);
[$message, $scope] = $this->getDepracatedMessage($deprecated);
$collector->addMessage($message, $scope);
}
@@ -1140,7 +1132,7 @@ class Debugger
protected function resolveCallable(callable $callable)
{
if (is_array($callable)) {
return get_class($callable[0]) . '->' . $callable[1] . '()';
return $callable[0]::class . '->' . $callable[1] . '()';
}
return 'unknown';

View File

@@ -70,7 +70,7 @@ class Errors
$logger = $grav['log'];
$whoops->pushHandler(function ($exception, $inspector, $run) use ($logger) {
try {
$logger->addCritical($exception->getMessage() . ' - Trace: ' . $exception->getTraceAsString());
$logger->critical($exception->getMessage() . ' - Trace: ' . $exception->getTraceAsString());
} catch (Exception $e) {
echo $e;
}

View File

@@ -54,11 +54,7 @@ class SimplePageHandler extends Handler
$code = Misc::translateErrorCode($code);
}
$vars = array(
'stylesheet' => file_get_contents($cssFile),
'code' => $code,
'message' => htmlspecialchars(strip_tags(rawurldecode($message)), ENT_QUOTES, 'UTF-8'),
);
$vars = ['stylesheet' => file_get_contents($cssFile), 'code' => $code, 'message' => htmlspecialchars(strip_tags(rawurldecode($message)), ENT_QUOTES, 'UTF-8')];
$helper->setVariables($vars);
$helper->render($templateFile);

View File

@@ -28,28 +28,27 @@ trait CompiledFile
/**
* Get/set parsed file contents.
*
* @param mixed $var
* @return array
*/
public function content($var = null)
public function content(mixed $var = null)
{
try {
$filename = $this->filename;
// If nothing has been loaded, attempt to get pre-compiled version of the file first.
if ($var === null && $this->raw === null && $this->content === null) {
$key = md5($filename);
$key = md5((string) $filename);
$file = PhpFile::instance(CACHE_DIR . "compiled/files/{$key}{$this->extension}.php");
$modified = $this->modified();
if (!$modified) {
try {
return $this->decode($this->raw());
} catch (Throwable $e) {
} catch (Throwable) {
// If the compiled file is broken, we can safely ignore the error and continue.
}
}
$class = get_class($this);
$class = $this::class;
$size = filesize($filename);
$cache = $file->exists() ? $file->content() : null;
@@ -115,7 +114,7 @@ trait CompiledFile
* @return void
* @throws RuntimeException
*/
public function save($data = null)
public function save(mixed $data = null)
{
// Make sure that the cache file is always up to date!
$key = md5($this->filename);
@@ -135,7 +134,7 @@ trait CompiledFile
if ($locked) {
$modified = $this->modified();
$filename = $this->filename;
$class = get_class($this);
$class = $this::class;
$size = filesize($filename);
// windows doesn't play nicely with this as it can't read when locked

View File

@@ -75,21 +75,21 @@ abstract class Archiver
* @param callable|null $status
* @return $this
*/
abstract public function compress($folder, callable $status = null);
abstract public function compress($folder, ?callable $status = null);
/**
* @param string $destination
* @param callable|null $status
* @return $this
*/
abstract public function extract($destination, callable $status = null);
abstract public function extract($destination, ?callable $status = null);
/**
* @param array $folders
* @param callable|null $status
* @return $this
*/
abstract public function addEmptyFolders($folders, callable $status = null);
abstract public function addEmptyFolders($folders, ?callable $status = null);
/**
* @param string $rootPath

View File

@@ -153,8 +153,8 @@ abstract class Folder
if ($base) {
$base = preg_replace('![\\\/]+!', '/', $base);
$path = preg_replace('![\\\/]+!', '/', $path);
if (strpos($path, $base) === 0) {
$path = ltrim(substr($path, strlen($base)), '/');
if (str_starts_with((string) $path, (string) $base)) {
$path = ltrim(substr((string) $path, strlen((string) $base)), '/');
}
}
@@ -178,8 +178,8 @@ abstract class Folder
return '';
}
$baseParts = explode('/', ltrim($base, '/'));
$pathParts = explode('/', ltrim($path, '/'));
$baseParts = explode('/', ltrim((string) $base, '/'));
$pathParts = explode('/', ltrim((string) $path, '/'));
array_pop($baseParts);
$lastPart = array_pop($pathParts);
@@ -194,7 +194,7 @@ abstract class Folder
$path = str_repeat('../', count($baseParts)) . implode('/', $pathParts);
return '' === $path
|| strpos($path, '/') === 0
|| str_starts_with($path, '/')
|| false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
? "./$path" : $path;
}
@@ -266,7 +266,7 @@ abstract class Folder
/** @var RecursiveDirectoryIterator $file */
foreach ($iterator as $file) {
// Ignore hidden files.
if (strpos($file->getFilename(), '.') === 0 && $file->isFile()) {
if (str_starts_with($file->getFilename(), '.') && $file->isFile()) {
continue;
}
if (!$folders && $file->isDir()) {
@@ -275,7 +275,7 @@ abstract class Folder
if (!$files && $file->isFile()) {
continue;
}
if ($compare && $pattern && !preg_match($pattern, $file->{$compare}())) {
if ($compare && $pattern && !preg_match($pattern, (string) $file->{$compare}())) {
continue;
}
$fileKey = $key ? $file->{$key}() : null;
@@ -283,14 +283,14 @@ abstract class Folder
if ($filters) {
if (isset($filters['key'])) {
$pre = !empty($filters['pre-key']) ? $filters['pre-key'] : '';
$fileKey = $pre . preg_replace($filters['key'], '', $fileKey);
$fileKey = $pre . preg_replace($filters['key'], '', (string) $fileKey);
}
if (isset($filters['value'])) {
$filter = $filters['value'];
if (is_callable($filter)) {
$filePath = $filter($file);
} else {
$filePath = preg_replace($filter, '', $filePath);
$filePath = preg_replace($filter, '', (string) $filePath);
}
}
}
@@ -331,7 +331,7 @@ abstract class Folder
// Go through all sub-directories and copy everything.
$files = self::all($source);
foreach ($files as $file) {
if ($ignore && preg_match($ignore, $file)) {
if ($ignore && preg_match($ignore, (string) $file)) {
continue;
}
$src = $source .'/'. $file;
@@ -377,7 +377,7 @@ abstract class Folder
return;
}
if (strpos($target, $source . '/') === 0) {
if (str_starts_with($target, $source . '/')) {
throw new RuntimeException('Cannot move folder to itself');
}

View File

@@ -63,8 +63,8 @@ class RecursiveDirectoryFilterIterator extends RecursiveFilterIterator
}
// Check if any parent directory is in the ignore list
foreach ($this::$ignore_folders as $ignore_folder) {
$ignore_folder = trim($ignore_folder, '/');
if (strpos($relative_filename, $ignore_folder . '/') === 0 || $relative_filename === $ignore_folder) {
$ignore_folder = trim((string) $ignore_folder, '/');
if (str_starts_with($relative_filename, $ignore_folder . '/') || $relative_filename === $ignore_folder) {
return false;
}
}
@@ -92,12 +92,12 @@ class RecursiveDirectoryFilterIterator extends RecursiveFilterIterator
return true;
}
// Check for extension patterns like .pdf
if (strpos($pattern, '.') === 0 && substr($filename, -strlen($pattern)) === $pattern) {
if (str_starts_with((string) $pattern, '.') && str_ends_with($filename, (string) $pattern)) {
return true;
}
// Check for wildcard patterns
if (strpos($pattern, '*') !== false) {
$regex = '/^' . str_replace('\\*', '.*', preg_quote($pattern, '/')) . '$/';
if (str_contains((string) $pattern, '*')) {
$regex = '/^' . str_replace('\\*', '.*', preg_quote((string) $pattern, '/')) . '$/';
if (preg_match($regex, $filename)) {
return true;
}

View File

@@ -26,7 +26,7 @@ class ZipArchiver extends Archiver
* @param callable|null $status
* @return $this
*/
public function extract($destination, callable $status = null)
public function extract($destination, ?callable $status = null)
{
$zip = new ZipArchive();
$archive = $zip->open($this->archive_file);
@@ -51,7 +51,7 @@ class ZipArchiver extends Archiver
* @param callable|null $status
* @return $this
*/
public function compress($source, callable $status = null)
public function compress($source, ?callable $status = null)
{
if (!extension_loaded('zip')) {
throw new InvalidArgumentException('ZipArchiver: Zip PHP module not installed...');
@@ -90,7 +90,7 @@ class ZipArchiver extends Archiver
foreach ($files as $file) {
$filePath = $file->getPathname();
$relativePath = ltrim(substr($filePath, strlen($rootPath)), '/');
$relativePath = ltrim(substr((string) $filePath, strlen($rootPath)), '/');
if ($file->isDir()) {
$zip->addEmptyDir($relativePath);
@@ -118,7 +118,7 @@ class ZipArchiver extends Archiver
* @param callable|null $status
* @return $this
*/
public function addEmptyFolders($folders, callable $status = null)
public function addEmptyFolders($folders, ?callable $status = null)
{
if (!extension_loaded('zip')) {
throw new InvalidArgumentException('ZipArchiver: Zip PHP module not installed...');

View File

@@ -32,7 +32,7 @@ abstract class FlexObject extends \Grav\Framework\Flex\FlexObject implements Med
* {@inheritdoc}
* @see FlexObjectInterface::getFormValue()
*/
public function getFormValue(string $name, $default = null, string $separator = null)
public function getFormValue(string $name, $default = null, ?string $separator = null)
{
$value = $this->getNestedProperty($name, null, $separator);

View File

@@ -35,7 +35,7 @@ trait FlexCollectionTrait
'collection' => $this
]);
}
if (strpos($name, 'onFlexCollection') !== 0 && strpos($name, 'on') === 0) {
if (!str_starts_with($name, 'onFlexCollection') && str_starts_with($name, 'on')) {
$name = 'onFlexCollection' . substr($name, 2);
}

View File

@@ -46,7 +46,7 @@ trait FlexObjectTrait
if (isset($events['name'])) {
$name = $events['name'];
} elseif (strpos($name, 'onFlexObject') !== 0 && strpos($name, 'on') === 0) {
} elseif (!str_starts_with($name, 'onFlexObject') && str_starts_with($name, 'on')) {
$name = 'onFlexObject' . substr($name, 2);
}

View File

@@ -172,7 +172,7 @@ class PageCollection extends FlexPageCollection implements PageCollectionInterfa
* @return static
* @phpstan-return static<T>
*/
public function merge(PageCollectionInterface $collection)
public function merge(PageCollectionInterface $collection): never
{
throw new RuntimeException(__METHOD__ . '(): Not Implemented');
}
@@ -184,7 +184,7 @@ class PageCollection extends FlexPageCollection implements PageCollectionInterfa
* @return static
* @phpstan-return static<T>
*/
public function intersect(PageCollectionInterface $collection)
public function intersect(PageCollectionInterface $collection): never
{
throw new RuntimeException(__METHOD__ . '(): Not Implemented');
}
@@ -242,7 +242,7 @@ class PageCollection extends FlexPageCollection implements PageCollectionInterfa
* @return static
* @phpstan-return static<T>
*/
public function append($items)
public function append($items): never
{
throw new RuntimeException(__METHOD__ . '(): Not Implemented');
}
@@ -303,7 +303,7 @@ class PageCollection extends FlexPageCollection implements PageCollectionInterfa
// do this header query work only once
$header_query = null;
$header_default = null;
if (strpos($order_by, 'header.') === 0) {
if (str_starts_with($order_by, 'header.')) {
$query = explode('|', str_replace('header.', '', $order_by), 2);
$header_query = array_shift($query) ?? '';
$header_default = array_shift($query);
@@ -373,9 +373,7 @@ class PageCollection extends FlexPageCollection implements PageCollectionInterfa
if ($col) {
$col->setAttribute(Collator::NUMERIC_COLLATION, Collator::ON);
if (($sort_flags & SORT_NATURAL) === SORT_NATURAL) {
$list = preg_replace_callback('~([0-9]+)\.~', static function ($number) {
return sprintf('%032d.', $number[0]);
}, $list);
$list = preg_replace_callback('~([0-9]+)\.~', static fn($number) => sprintf('%032d.', $number[0]), $list);
if (!is_array($list)) {
throw new RuntimeException('Internal Error');
}
@@ -457,7 +455,7 @@ class PageCollection extends FlexPageCollection implements PageCollectionInterfa
continue;
}
$date = $field ? strtotime($object->getNestedProperty($field)) : $object->date();
$date = $field ? strtotime((string) $object->getNestedProperty($field)) : $object->date();
if ((!$start || $date >= $start) && (!$end || $date <= $end)) {
$entries[$key] = $object;
@@ -766,7 +764,7 @@ class PageCollection extends FlexPageCollection implements PageCollectionInterfa
* @return static
* @phpstan-return static<T>
*/
public function withTranslation(bool $bool = true, string $languageCode = null, bool $fallback = null)
public function withTranslation(bool $bool = true, ?string $languageCode = null, ?bool $fallback = null)
{
$list = array_keys(array_filter($this->call('hasTranslation', [$languageCode, $fallback])));
@@ -778,7 +776,7 @@ class PageCollection extends FlexPageCollection implements PageCollectionInterfa
* @param bool|null $fallback
* @return PageIndex
*/
public function withTranslated(string $languageCode = null, bool $fallback = null)
public function withTranslated(?string $languageCode = null, ?bool $fallback = null)
{
return $this->getIndex()->withTranslated($languageCode, $fallback);
}

View File

@@ -57,7 +57,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
public const ORDER_LIST_REGEX = '/(\/\d+)\.[^\/]+/u';
public const PAGE_ROUTE_REGEX = '/\/\d+\./u';
/** @var PageObject|array */
/** @var T|array */
protected $_root;
/** @var array|null */
protected $_params;
@@ -66,7 +66,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
* @param array $entries
* @param FlexDirectory|null $directory
*/
public function __construct(array $entries = [], FlexDirectory $directory = null)
public function __construct(array $entries = [], ?FlexDirectory $directory = null)
{
// Remove root if it's taken.
if (isset($entries[''])) {
@@ -181,7 +181,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
* @return static
* @phpstan-return static<T,C>
*/
public function withTranslated(string $languageCode = null, bool $fallback = null)
public function withTranslated(?string $languageCode = null, ?bool $fallback = null)
{
if (null === $languageCode) {
return $this;
@@ -239,10 +239,9 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
* Set a parameter to the Collection
*
* @param string $name
* @param mixed $value
* @return $this
*/
public function setParam(string $name, $value)
public function setParam(string $name, mixed $value)
{
$this->_params[$name] = $value;
@@ -413,7 +412,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
* @return static
* @phpstan-return static<T,C>
*/
protected function createFrom(array $entries, string $keyField = null)
protected function createFrom(array $entries, ?string $keyField = null)
{
/** @var static $index */
$index = parent::createFrom($entries, $keyField);
@@ -428,7 +427,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
* @param bool|null $fallback
* @return array
*/
protected function translateEntries(array $entries, string $lang, bool $fallback = null): array
protected function translateEntries(array $entries, string $lang, ?bool $fallback = null): array
{
$languages = $this->getFallbackLanguages($lang, $fallback);
foreach ($entries as $key => &$entry) {
@@ -493,9 +492,9 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
* @param bool|null $fallback
* @return array
*/
protected function getFallbackLanguages(string $languageCode = null, bool $fallback = null): array
protected function getFallbackLanguages(?string $languageCode = null, ?bool $fallback = null): array
{
$fallback = $fallback ?? true;
$fallback ??= true;
if (!$fallback && null !== $languageCode) {
return [$languageCode];
}
@@ -504,7 +503,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
/** @var Language $language */
$language = $grav['language'];
$languageCode = $languageCode ?? '';
$languageCode ??= '';
if ($languageCode === '' && $fallback) {
return $language->getFallbackLanguages(null, true);
}
@@ -533,7 +532,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
// Handle leaf_route
$leaf = null;
if ($leaf_route && $route !== $leaf_route) {
$nodes = explode('/', $leaf_route);
$nodes = explode('/', (string) $leaf_route);
$sub_route = '/' . implode('/', array_slice($nodes, 1, $options['level']++));
$options['route'] = $sub_route;
@@ -544,7 +543,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
if (!$route) {
$page = $this->getRoot();
} else {
$page = $this->get(trim($route, '/'));
$page = $this->get(trim((string) $route, '/'));
}
$path = $page ? $page->path() : null;
@@ -558,7 +557,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
// Clean up filter.
$filter_type = (array)($filters['type'] ?? []);
unset($filters['type']);
$filters = array_filter($filters, static function($val) { return $val !== null && $val !== ''; });
$filters = array_filter($filters, static fn($val) => $val !== null && $val !== '');
if ($page) {
$status = 'success';
@@ -682,9 +681,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
'tags' => $tags,
'actions' => $this->getListingActions($child, $user),
];
$extras = array_filter($extras, static function ($v) {
return $v !== null;
});
$extras = array_filter($extras, static fn($v) => $v !== null);
/** @var PageIndex $tmp */
$tmp = $child->children()->getIndex();
@@ -698,7 +695,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
'title' => htmlspecialchars($child->menu()),
'route' => [
'display' => htmlspecialchars($route) ?: null,
'raw' => htmlspecialchars($child->rawRoute()),
'raw' => htmlspecialchars((string) $child->rawRoute()),
],
'modified' => $this->jsDate($child->modified()),
'child_count' => $child_count ?: null,
@@ -706,9 +703,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
'filters_hit' => $filters ? ($child->filterBy($filters, false) ?: null) : null,
'extras' => $extras
];
$payload = array_filter($payload, static function ($v) {
return $v !== null;
});
$payload = array_filter($payload, static fn($v) => $v !== null);
}
// Add children if any
@@ -781,7 +776,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
* @param int|null $timestamp
* @return string|null
*/
private function jsDate(int $timestamp = null): ?string
private function jsDate(?int $timestamp = null): ?string
{
if (!$timestamp) {
return null;

View File

@@ -129,7 +129,7 @@ class PageObject extends FlexPageObject
/**
* @inheritdoc PageInterface
*/
public function getFormValue(string $name, $default = null, string $separator = null)
public function getFormValue(string $name, $default = null, ?string $separator = null)
{
$test = new stdClass();
@@ -261,7 +261,7 @@ class PageObject extends FlexPageObject
/**
* @param UserInterface|null $user
*/
public function check(UserInterface $user = null): void
public function check(?UserInterface $user = null): void
{
parent::check($user);
@@ -521,7 +521,7 @@ class PageObject extends FlexPageObject
$template = $this->getProperty('template') . ($name ? '.' . $name : '');
$blueprint = $this->getFlexDirectory()->getBlueprint($template, 'blueprints://pages');
} catch (RuntimeException $e) {
} catch (RuntimeException) {
$template = 'default' . ($name ? '.' . $name : '');
$blueprint = $this->getFlexDirectory()->getBlueprint($template, 'blueprints://pages');
@@ -554,7 +554,7 @@ class PageObject extends FlexPageObject
$initial = $options['initial'] ?? null;
$var = $initial ? 'leaf_route' : 'route';
$route = $options[$var] ?? '';
if ($route !== '' && !str_starts_with($route, '/')) {
if ($route !== '' && !str_starts_with((string) $route, '/')) {
$filesystem = Filesystem::getInstance();
$route = "/{$this->getKey()}/{$route}";
@@ -600,7 +600,7 @@ class PageObject extends FlexPageObject
$matches = $test->search((string)$value) > 0.0;
break;
case 'page_type':
$types = $value ? explode(',', $value) : [];
$types = $value ? explode(',', (string) $value) : [];
$matches = in_array($test->template(), $types, true);
break;
case 'extension':
@@ -698,7 +698,7 @@ class PageObject extends FlexPageObject
} elseif (array_key_exists('ordering', $elements) && array_key_exists('order', $elements)) {
// Store ordering.
$ordering = $elements['order'] ?? null;
$this->_reorder = !empty($ordering) ? explode(',', $ordering) : [];
$this->_reorder = !empty($ordering) ? explode(',', (string) $ordering) : [];
$order = false;
if ((bool)($elements['ordering'] ?? false)) {

View File

@@ -394,14 +394,14 @@ class PageStorage extends FolderStorage
if ($oldFolder !== $newFolder && file_exists($oldFolder)) {
$isCopy = $row['__META']['copy'] ?? false;
if ($isCopy) {
if (strpos($newFolder, $oldFolder . '/') === 0) {
if (str_starts_with($newFolder, $oldFolder . '/')) {
throw new RuntimeException(sprintf('Page /%s cannot be copied to itself', $oldKey));
}
$this->copyRow($oldKey, $newKey);
$debugger->addMessage("Page copied: {$oldFolder} => {$newFolder}", 'debug');
} else {
if (strpos($newFolder, $oldFolder . '/') === 0) {
if (str_starts_with($newFolder, $oldFolder . '/')) {
throw new RuntimeException(sprintf('Page /%s cannot be moved to itself', $oldKey));
}
@@ -538,7 +538,7 @@ class PageStorage extends FolderStorage
if ($reload || !isset($this->meta[$key])) {
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
if (mb_strpos($key, '@@') === false) {
if (mb_strpos((string) $key, '@@') === false) {
$path = $this->getStoragePath($key);
if (is_string($path)) {
$path = $locator->isStream($path) ? $locator->findResource($path) : GRAV_ROOT . "/{$path}";

View File

@@ -32,7 +32,7 @@ trait PageRoutableTrait
* @return PageInterface|null the parent page object if it exists.
*/
public function parent(PageInterface $var = null)
public function parent(?PageInterface $var = null)
{
if (Utils::isAdminPlugin()) {
return parent::parent();

View File

@@ -92,9 +92,7 @@ trait PageTranslateTrait
$list[$languageCode ?: $defaultCode] = $route ?? '';
}
$list = array_filter($list, static function ($var) {
return null !== $var;
});
$list = array_filter($list, static fn($var) => null !== $var);
// Hack to get the same result as with old pages.
foreach ($list as &$path) {

View File

@@ -38,7 +38,7 @@ class UserGroupCollection extends FlexCollection
* @param string|null $scope
* @return bool|null
*/
public function authorize(string $action, string $scope = null): ?bool
public function authorize(string $action, ?string $scope = null): ?bool
{
$authorized = null;
/** @var UserGroupObject $object */

View File

@@ -57,7 +57,7 @@ class UserGroupObject extends FlexObject implements UserGroupInterface
* @param string|null $scope
* @return bool|null
*/
public function authorize(string $action, string $scope = null): ?bool
public function authorize(string $action, ?string $scope = null): ?bool
{
if ($scope === 'test') {
$scope = null;
@@ -100,10 +100,9 @@ class UserGroupObject extends FlexObject implements UserGroupInterface
}
/**
* @param mixed $value
* @return array
*/
protected function offsetLoad_access($value): array
protected function offsetLoad_access(mixed $value): array
{
if (!$value instanceof Access) {
$value = new Access($value);
@@ -115,10 +114,9 @@ class UserGroupObject extends FlexObject implements UserGroupInterface
}
/**
* @param mixed $value
* @return array
*/
protected function offsetPrepare_access($value): array
protected function offsetPrepare_access(mixed $value): array
{
return $this->offsetLoad_access($value);
}

View File

@@ -23,7 +23,7 @@ class UserFileStorage extends FileStorage
* {@inheritdoc}
* @see FlexStorageInterface::getMediaPath()
*/
public function getMediaPath(string $key = null): ?string
public function getMediaPath(?string $key = null): ?string
{
// There is no media support for file storage (fallback to common location).
return null;

View File

@@ -30,7 +30,7 @@ trait UserObjectLegacyTrait
*/
public function merge(array $data)
{
user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use ->update($data) method instead', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use ->update($data) method instead', E_USER_DEPRECATED);
$this->setElements($this->getBlueprint()->mergeData($this->toArray(), $data));
@@ -45,7 +45,7 @@ trait UserObjectLegacyTrait
*/
public function getAvatarMedia()
{
user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use ->getAvatarImage() method instead', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use ->getAvatarImage() method instead', E_USER_DEPRECATED);
return $this->getAvatarImage();
}
@@ -58,7 +58,7 @@ trait UserObjectLegacyTrait
*/
public function avatarUrl()
{
user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use ->getAvatarUrl() method instead', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use ->getAvatarUrl() method instead', E_USER_DEPRECATED);
return $this->getAvatarUrl();
}
@@ -73,7 +73,7 @@ trait UserObjectLegacyTrait
*/
public function authorise($action)
{
user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.5, use ->authorize() method instead', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '() is deprecated since Grav 1.5, use ->authorize() method instead', E_USER_DEPRECATED);
return $this->authorize($action) ?? false;
}
@@ -87,7 +87,7 @@ trait UserObjectLegacyTrait
#[\ReturnTypeWillChange]
public function count()
{
user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6', E_USER_DEPRECATED);
return count($this->jsonSerialize());
}

View File

@@ -67,7 +67,7 @@ class UserIndex extends FlexIndex implements UserCollectionInterface
// Username can also be number and stored as such.
$key = (string)($data['username'] ?? $meta['key'] ?? $meta['storage_key']);
$meta['key'] = static::filterUsername($key, $storage);
$meta['email'] = isset($data['email']) ? mb_strtolower($data['email']) : null;
$meta['email'] = isset($data['email']) ? mb_strtolower((string) $data['email']) : null;
}
/**
@@ -197,7 +197,7 @@ class UserIndex extends FlexIndex implements UserCollectionInterface
/** @var Logger $logger */
$logger = $grav['log'];
$logger->addDebug($message);
$logger->debug($message);
/** @var Debugger $debugger */
$debugger = $grav['debugger'];

View File

@@ -92,9 +92,9 @@ class UserObject extends FlexObject implements UserInterface, Countable
protected $_uploads_original;
/** @var FileInterface|null */
protected $_storage;
/** @var UserGroupIndex */
/** @var UserGroupIndex|null */
protected $_groups;
/** @var Access */
/** @var Access|null */
protected $_access;
/** @var array|null */
protected $access;
@@ -270,7 +270,7 @@ class UserObject extends FlexObject implements UserInterface, Countable
* @param string|null $scope
* @return bool|null
*/
public function authorize(string $action, string $scope = null): ?bool
public function authorize(string $action, ?string $scope = null): ?bool
{
if ($scope === 'test') {
// Special scope to test user permissions.
@@ -286,7 +286,7 @@ class UserObject extends FlexObject implements UserInterface, Countable
return false;
}
if (strpos($action, 'login') === false && !$this->getProperty('authorized')) {
if (!str_contains($action, 'login') && !$this->getProperty('authorized')) {
// User needs to be authorized (2FA).
return false;
}
@@ -401,7 +401,7 @@ class UserObject extends FlexObject implements UserInterface, Countable
*/
public function join($name, $value, $separator = null)
{
$separator = $separator ?? '.';
$separator ??= '.';
$old = $this->get($name, null, $separator);
if ($old !== null) {
if (!is_array($old)) {
@@ -557,7 +557,7 @@ class UserObject extends FlexObject implements UserInterface, Countable
* @param FileInterface|null $storage Optionally enter a new storage.
* @return FileInterface|null
*/
public function file(FileInterface $storage = null)
public function file(?FileInterface $storage = null)
{
if (null !== $storage) {
$this->_storage = $storage;
@@ -1027,10 +1027,9 @@ class UserObject extends FlexObject implements UserInterface, Countable
}
/**
* @param mixed $value
* @return array
*/
protected function offsetLoad_access($value): array
protected function offsetLoad_access(mixed $value): array
{
if (!$value instanceof Access) {
$value = new Access($value);
@@ -1040,10 +1039,9 @@ class UserObject extends FlexObject implements UserInterface, Countable
}
/**
* @param mixed $value
* @return array
*/
protected function offsetPrepare_access($value): array
protected function offsetPrepare_access(mixed $value): array
{
return $this->offsetLoad_access($value);
}

View File

@@ -28,7 +28,7 @@ class FormFlash extends FrameworkFormFlash
{
$fields = [];
foreach ($this->files as $field => $files) {
if (strpos($field, '/')) {
if (strpos((string) $field, '/')) {
continue;
}
foreach ($files as $file) {

View File

@@ -14,7 +14,7 @@ use Grav\Common\Data\Data;
/**
* @property string $name
*/
class Package
class Package implements \Stringable
{
/** @var Data */
protected $data;
@@ -53,11 +53,10 @@ class Package
/**
* @param string $key
* @param mixed $value
* @return void
*/
#[\ReturnTypeWillChange]
public function __set($key, $value)
public function __set($key, mixed $value)
{
$this->data->set($key, $value);
}
@@ -76,7 +75,7 @@ class Package
* @return string
*/
#[\ReturnTypeWillChange]
public function __toString()
public function __toString(): string
{
return $this->toJson();
}

View File

@@ -37,8 +37,6 @@ class GPM extends Iterator
private $repository;
/** @var Remote\GravCore|null Remove Grav Packages */
private $grav;
/** @var bool */
private $refresh;
/** @var callable|null */
private $callback;
@@ -57,7 +55,7 @@ class GPM extends Iterator
* @param bool $refresh Applies to Remote Packages only and forces a refetch of data
* @param callable|null $callback Either a function or callback in array notation
*/
public function __construct($refresh = false, $callback = null)
public function __construct(private $refresh = false, $callback = null)
{
parent::__construct();
@@ -65,7 +63,6 @@ class GPM extends Iterator
$this->cache = [];
$this->installed = new Local\Packages();
$this->refresh = $refresh;
$this->callback = $callback;
}
@@ -78,12 +75,10 @@ class GPM extends Iterator
#[\ReturnTypeWillChange]
public function __get($offset)
{
switch ($offset) {
case 'grav':
return $this->getGrav();
}
return parent::__get($offset);
return match ($offset) {
'grav' => $this->getGrav(),
default => parent::__get($offset),
};
}
/**
@@ -95,12 +90,10 @@ class GPM extends Iterator
#[\ReturnTypeWillChange]
public function __isset($offset)
{
switch ($offset) {
case 'grav':
return $this->getGrav() !== null;
}
return parent::__isset($offset);
return match ($offset) {
'grav' => $this->getGrav() !== null,
default => parent::__isset($offset),
};
}
/**
@@ -126,7 +119,7 @@ class GPM extends Iterator
if ($type_installed === false) {
continue;
}
$methodInstallableType = 'getInstalled' . ucfirst($type);
$methodInstallableType = 'getInstalled' . ucfirst((string) $type);
$to_install = $this->$methodInstallableType();
$items[$type] = $to_install;
$items['total'] += count($to_install);
@@ -286,7 +279,7 @@ class GPM extends Iterator
if ($type_updatable === false) {
continue;
}
$methodUpdatableType = 'getUpdatable' . ucfirst($type);
$methodUpdatableType = 'getUpdatable' . ucfirst((string) $type);
$to_update = $this->$methodUpdatableType();
$items[$type] = $to_update;
$items['total'] += count($to_update);
@@ -550,7 +543,7 @@ class GPM extends Iterator
if (null === $this->repository) {
try {
$this->repository = new Remote\Packages($this->refresh, $this->callback);
} catch (Exception $e) {}
} catch (Exception) {}
}
return $this->repository;
@@ -566,7 +559,7 @@ class GPM extends Iterator
if (null === $this->grav) {
try {
$this->grav = new Remote\GravCore($this->refresh, $this->callback);
} catch (Exception $e) {}
} catch (Exception) {}
}
return $this->grav;
@@ -1220,7 +1213,7 @@ class GPM extends Iterator
*/
public function versionFormatIsNextSignificantRelease($version): bool
{
return strpos($version, '~') === 0;
return str_starts_with($version, '~');
}
/**
@@ -1233,7 +1226,7 @@ class GPM extends Iterator
*/
public function versionFormatIsEqualOrHigher($version): bool
{
return strpos($version, '>=') === 0;
return str_starts_with($version, '>=');
}
/**

View File

@@ -81,7 +81,7 @@ class Installer
{
$destination = rtrim($destination, DS);
$options = array_merge(self::$options, $options);
$install_path = rtrim($destination . DS . ltrim($options['install_path'], DS), DS);
$install_path = rtrim($destination . DS . ltrim((string) $options['install_path'], DS), DS);
if (!self::isGravInstance($destination) || !self::isValidDestination(
$install_path,

View File

@@ -37,7 +37,7 @@ class Package extends BasePackage
$html_description = Parsedown::instance()->line($this->__get('description'));
$this->data->set('slug', $package->__get('slug'));
$this->data->set('description_html', $html_description);
$this->data->set('description_plain', strip_tags($html_description));
$this->data->set('description_plain', strip_tags((string) $html_description));
$this->data->set('symlink', is_link(USER_DIR . $package_type . DS . $this->__get('slug')));
}

View File

@@ -12,7 +12,7 @@ namespace Grav\Common\GPM\Remote;
use Grav\Common\Grav;
use Grav\Common\HTTP\Response;
use Grav\Common\GPM\Common\AbstractPackageCollection as BaseCollection;
use \Doctrine\Common\Cache\FilesystemCache;
use Doctrine\Common\Cache\FilesystemCache;
use RuntimeException;
/**
@@ -53,10 +53,10 @@ class AbstractPackageCollection extends BaseCollection
$this->raw = $this->cache->fetch(md5($this->repository));
$this->fetch($refresh, $callback);
foreach (json_decode($this->raw, true) as $slug => $data) {
foreach (json_decode((string) $this->raw, true) as $slug => $data) {
// Temporarily fix for using multi-sites
if (isset($data['install_path'])) {
$path = preg_replace('~^user/~i', 'user://', $data['install_path']);
$path = preg_replace('~^user/~i', 'user://', (string) $data['install_path']);
$data['install_path'] = Grav::instance()['locator']->findResource($path, false, true);
}
$this->items[$slug] = new Package($data, $this->type);

View File

@@ -46,7 +46,7 @@ class GravCore extends AbstractPackageCollection
$this->fetch($refresh, $callback);
$this->data = json_decode($this->raw, true);
$this->data = json_decode((string) $this->raw, true);
$this->version = $this->data['version'] ?? '-';
$this->date = $this->data['date'] ?? '-';
$this->min_php = $this->data['min_php'] ?? null;
@@ -82,7 +82,7 @@ class GravCore extends AbstractPackageCollection
$diffLog = [];
foreach ((array)$this->data['changelog'] as $version => $changelog) {
preg_match("/[\w\-\.]+/", $version, $cleanVersion);
preg_match("/[\w\-\.]+/", (string) $version, $cleanVersion);
if (!$cleanVersion || version_compare($diff, $cleanVersion[0], '>=')) {
continue;

View File

@@ -52,7 +52,7 @@ class Package extends BasePackage implements \JsonSerializable
$diffLog = [];
foreach ((array)$this->data['changelog'] as $version => $changelog) {
preg_match("/[\w\-.]+/", $version, $cleanVersion);
preg_match("/[\w\-.]+/", (string) $version, $cleanVersion);
if (!$cleanVersion || version_compare($diff, $cleanVersion[0], '>=')) {
continue;

View File

@@ -29,7 +29,7 @@ abstract class Getters implements ArrayAccess, Countable
* @param mixed $value Medium value
*/
#[\ReturnTypeWillChange]
public function __set($offset, $value)
public function __set($offset, mixed $value)
{
$this->offsetSet($offset, $value);
}
@@ -103,10 +103,9 @@ abstract class Getters implements ArrayAccess, Countable
/**
* @param int|string $offset
* @param mixed $value
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
public function offsetSet($offset, mixed $value)
{
if ($this->gettersVariable) {
$var = $this->gettersVariable;

View File

@@ -200,7 +200,7 @@ class Grav extends Container
* @param string|null $environment
* @return $this
*/
public function setup(string $environment = null)
public function setup(?string $environment = null)
{
if (isset($this->initialized['setup'])) {
return $this;
@@ -261,51 +261,23 @@ class Grav extends Container
$container = new Container(
[
'multipartRequestSupport' => function () {
return new MultipartRequestSupport();
},
'initializeProcessor' => function () {
return new InitializeProcessor($this);
},
'backupsProcessor' => function () {
return new BackupsProcessor($this);
},
'pluginsProcessor' => function () {
return new PluginsProcessor($this);
},
'themesProcessor' => function () {
return new ThemesProcessor($this);
},
'schedulerProcessor' => function () {
return new SchedulerProcessor($this);
},
'requestProcessor' => function () {
return new RequestProcessor($this);
},
'tasksProcessor' => function () {
return new TasksProcessor($this);
},
'assetsProcessor' => function () {
return new AssetsProcessor($this);
},
'twigProcessor' => function () {
return new TwigProcessor($this);
},
'pagesProcessor' => function () {
return new PagesProcessor($this);
},
'debuggerAssetsProcessor' => function () {
return new DebuggerAssetsProcessor($this);
},
'renderProcessor' => function () {
return new RenderProcessor($this);
},
'multipartRequestSupport' => fn() => new MultipartRequestSupport(),
'initializeProcessor' => fn() => new InitializeProcessor($this),
'backupsProcessor' => fn() => new BackupsProcessor($this),
'pluginsProcessor' => fn() => new PluginsProcessor($this),
'themesProcessor' => fn() => new ThemesProcessor($this),
'schedulerProcessor' => fn() => new SchedulerProcessor($this),
'requestProcessor' => fn() => new RequestProcessor($this),
'tasksProcessor' => fn() => new TasksProcessor($this),
'assetsProcessor' => fn() => new AssetsProcessor($this),
'twigProcessor' => fn() => new TwigProcessor($this),
'pagesProcessor' => fn() => new PagesProcessor($this),
'debuggerAssetsProcessor' => fn() => new DebuggerAssetsProcessor($this),
'renderProcessor' => fn() => new RenderProcessor($this),
]
);
$default = static function () {
return new Response(404, ['Expires' => 0, 'Cache-Control' => 'no-store, max-age=0'], 'Not Found');
};
$default = static fn() => new Response(404, ['Expires' => 0, 'Cache-Control' => 'no-store, max-age=0'], 'Not Found');
$collection = new RequestHandler($this->middleware, $default, $container);
@@ -326,7 +298,7 @@ class Grav extends Container
$etag = md5($body);
$response = $response->withHeader('ETag', '"' . $etag . '"');
$search = trim($this['request']->getHeaderLine('If-None-Match'), '"');
$search = trim((string) $this['request']->getHeaderLine('If-None-Match'), '"');
if ($noCache === false && $search === $etag) {
$response = $response->withStatus(304);
$body = '';
@@ -403,7 +375,7 @@ class Grav extends Container
$etag = md5($body);
$response = $response->withHeader('ETag', '"' . $etag . '"');
$search = trim($this['request']->getHeaderLine('If-None-Match'), '"');
$search = trim((string) $this['request']->getHeaderLine('If-None-Match'), '"');
if ($noCache === false && $search === $etag) {
$response = $response->withStatus(304);
$body = '';
@@ -461,7 +433,7 @@ class Grav extends Container
if (null === $code) {
// Check for redirect code in the route: e.g. /new/[301], /new[301]/route or /new[301].html
$regex = '/.*(\[(30[1-7])\])(.\w+|\/.*?)?$/';
preg_match($regex, $route, $matches);
preg_match($regex, (string) $route, $matches);
if ($matches) {
$route = str_replace($matches[1], '', $matches[0]);
$code = $matches[2];
@@ -474,9 +446,9 @@ class Grav extends Container
$url = rtrim($uri->rootUrl(), '/') . '/';
if ($this['config']->get('system.pages.redirect_trailing_slash', true)) {
$url .= trim($route, '/'); // Remove trailing slash
$url .= trim((string) $route, '/'); // Remove trailing slash
} else {
$url .= ltrim($route, '/'); // Support trailing slash default routes
$url .= ltrim((string) $route, '/'); // Support trailing slash default routes
}
}
} elseif ($route instanceof Route) {
@@ -522,7 +494,7 @@ class Grav extends Container
* @param ResponseInterface|null $response
* @return void
*/
public function header(ResponseInterface $response = null): void
public function header(?ResponseInterface $response = null): void
{
if (null === $response) {
/** @var PageInterface $page */
@@ -533,7 +505,7 @@ class Grav extends Container
header("HTTP/{$response->getProtocolVersion()} {$response->getStatusCode()} {$response->getReasonPhrase()}");
foreach ($response->getHeaders() as $key => $values) {
// Skip internal Grav headers.
if (strpos($key, 'Grav-Internal-') === 0) {
if (str_starts_with((string) $key, 'Grav-Internal-')) {
continue;
}
foreach ($values as $i => $value) {
@@ -552,7 +524,7 @@ class Grav extends Container
// Initialize Locale if set and configured.
if ($this['language']->enabled() && $this['config']->get('system.languages.override_locale')) {
$language = $this['language']->getLanguage();
setlocale(LC_ALL, strlen($language) < 3 ? ($language . '_' . strtoupper($language)) : $language);
setlocale(LC_ALL, strlen((string) $language) < 3 ? ($language . '_' . strtoupper((string) $language)) : $language);
} elseif ($this['config']->get('system.default_locale')) {
setlocale(LC_ALL, $this['config']->get('system.default_locale'));
}
@@ -566,7 +538,7 @@ class Grav extends Container
{
/** @var EventDispatcherInterface $events */
$events = $this['events'];
$eventName = get_class($event);
$eventName = $event::class;
$timestamp = microtime(true);
$event = $events->dispatch($event);
@@ -585,7 +557,7 @@ class Grav extends Container
* @param Event|null $event
* @return Event
*/
public function fireEvent($eventName, Event $event = null)
public function fireEvent($eventName, ?Event $event = null)
{
/** @var EventDispatcherInterface $events */
$events = $this['events'];
@@ -734,9 +706,7 @@ class Grav extends Container
if (is_int($serviceKey)) {
$this->register(new $serviceClass);
} else {
$this[$serviceKey] = function ($c) use ($serviceClass) {
return new $serviceClass($c);
};
$this[$serviceKey] = fn($c) => new $serviceClass($c);
}
}
}
@@ -799,7 +769,7 @@ class Grav extends Container
$medium = $media[$media_file];
foreach ($uri->query(null, true) as $action => $params) {
if (in_array($action, ImageMedium::$magic_actions, true)) {
call_user_func_array([&$medium, $action], explode(',', $params));
call_user_func_array([&$medium, $action], explode(',', (string) $params));
}
}
Utils::download($medium->path(), false);
@@ -816,7 +786,7 @@ class Grav extends Container
if ($extension) {
$download = true;
if (in_array(ltrim($extension, '.'), $config->get('system.media.unsupported_inline_types', []), true)) {
if (in_array(ltrim((string) $extension, '.'), $config->get('system.media.unsupported_inline_types', []), true)) {
$download = false;
}
Utils::download($page->path() . DIRECTORY_SEPARATOR . $uri->basename(), $download);

View File

@@ -25,7 +25,7 @@ class Client
'User-Agent' => 'Grav CMS'
];
public static function getClient(array $overrides = [], int $connections = 6, callable $callback = null): HttpClientInterface
public static function getClient(array $overrides = [], int $connections = 6, ?callable $callback = null): HttpClientInterface
{
$config = Grav::instance()['config'];
$options = static::getOptions();
@@ -33,7 +33,7 @@ class Client
// Use callback if provided
if ($callback) {
self::$callback = $callback;
$options->setOnProgress([Client::class, 'progress']);
$options->setOnProgress(Client::progress(...));
}
$settings = array_merge($options->toArray(), $overrides);
@@ -43,17 +43,11 @@ class Client
$preferred_method = $config->get('system.gpm.method', 'auto');
}
switch ($preferred_method) {
case 'curl':
$client = new CurlHttpClient($settings, $connections);
break;
case 'fopen':
case 'native':
$client = new NativeHttpClient($settings, $connections);
break;
default:
$client = HttpClient::create($settings, $connections);
}
$client = match ($preferred_method) {
'curl' => new CurlHttpClient($settings, $connections),
'fopen', 'native' => new NativeHttpClient($settings, $connections),
default => HttpClient::create($settings, $connections),
};
return $client;
}

View File

@@ -41,7 +41,7 @@ class Response
* @return string
* @throws TransportExceptionInterface|RedirectionExceptionInterface|ServerExceptionInterface|TransportExceptionInterface|ClientExceptionInterface
*/
public static function get(string $uri = '', array $overrides = [], callable $callback = null): string
public static function get(string $uri = '', array $overrides = [], ?callable $callback = null): string
{
$response = static::request('GET', $uri, $overrides, $callback);
return $response->getContent();
@@ -58,7 +58,7 @@ class Response
* @return ResponseInterface
* @throws TransportExceptionInterface
*/
public static function request(string $method, string $uri, array $overrides = [], callable $callback = null): ResponseInterface
public static function request(string $method, string $uri, array $overrides = [], ?callable $callback = null): ResponseInterface
{
if (empty($method)) {
throw new TransportException('missing method (GET, PUT, etc.)');
@@ -73,7 +73,7 @@ class Response
if (Utils::functionExists('set_time_limit')) {
@set_time_limit(0);
}
} catch (Exception $e) {}
} catch (Exception) {}
$client = Client::getClient($overrides, 6, $callback);

View File

@@ -30,7 +30,7 @@ class Excerpts
* @param PageInterface|null $page Page, defaults to the current page object
* @return string Returns final HTML string
*/
public static function processImageHtml($html, PageInterface $page = null)
public static function processImageHtml($html, ?PageInterface $page = null)
{
$excerpt = static::getExcerptFromHtml($html, 'img');
if (null === $excerpt) {
@@ -61,7 +61,7 @@ class Excerpts
* @param PageInterface|null $page Page, defaults to the current page object
* @return string Returns final HTML string
*/
public static function processLinkHtml($html, PageInterface $page = null)
public static function processLinkHtml($html, ?PageInterface $page = null)
{
$excerpt = static::getExcerptFromHtml($html, 'a');
if (null === $excerpt) {
@@ -158,7 +158,7 @@ class Excerpts
* @param string $type
* @return mixed
*/
public static function processLinkExcerpt($excerpt, PageInterface $page = null, $type = 'link')
public static function processLinkExcerpt($excerpt, ?PageInterface $page = null, $type = 'link')
{
$excerpts = new ExcerptsObject($page);
@@ -172,7 +172,7 @@ class Excerpts
* @param PageInterface|null $page Page, defaults to the current page object
* @return array
*/
public static function processImageExcerpt(array $excerpt, PageInterface $page = null)
public static function processImageExcerpt(array $excerpt, ?PageInterface $page = null)
{
$excerpts = new ExcerptsObject($page);
@@ -187,7 +187,7 @@ class Excerpts
* @param PageInterface|null $page Page, defaults to the current page object
* @return Medium|Link
*/
public static function processMediaActions($medium, $url, PageInterface $page = null)
public static function processMediaActions($medium, $url, ?PageInterface $page = null)
{
$excerpts = new ExcerptsObject($page);

View File

@@ -60,9 +60,9 @@ class Truncator
$words = $currentWordPosition[2];
$curNode->nodeValue = substr(
$curNode->nodeValue,
(string) $curNode->nodeValue,
0,
$words[$offset][1] + strlen($words[$offset][0])
$words[$offset][1] + strlen((string) $words[$offset][0])
);
self::removeProceedingNodes($curNode, $container);
@@ -110,7 +110,7 @@ class Truncator
// If we have exceeded the limit, we want to delete the remainder of this document.
if ($letters->key() >= $limit) {
$currentText = $letters->currentTextPosition();
$currentText[0]->nodeValue = mb_substr($currentText[0]->nodeValue, 0, $currentText[1] + 1);
$currentText[0]->nodeValue = mb_substr((string) $currentText[0]->nodeValue, 0, $currentText[1] + 1);
self::removeProceedingNodes($currentText[0], $container);
if (!empty($ellipsis)) {
@@ -216,7 +216,7 @@ class Truncator
*/
private static function insertEllipsis($domNode, $ellipsis)
{
$avoid = array('a', 'strong', 'em', 'h1', 'h2', 'h3', 'h4', 'h5'); //html tags to avoid appending the ellipsis to
$avoid = ['a', 'strong', 'em', 'h1', 'h2', 'h3', 'h4', 'h5']; //html tags to avoid appending the ellipsis to
if ($domNode->parentNode->parentNode !== null && in_array($domNode->parentNode->nodeName, $avoid, true)) {
// Append as text node to parent instead
@@ -231,7 +231,7 @@ class Truncator
}
} else {
// Append to current node
$domNode->nodeValue = rtrim($domNode->nodeValue) . $ellipsis;
$domNode->nodeValue = rtrim((string) $domNode->nodeValue) . $ellipsis;
}
}
@@ -252,7 +252,7 @@ class Truncator
) {
if ($considerHtml) {
// if the plain text is shorter than the maximum length, return the whole text
if (strlen(preg_replace('/<.*?>/', '', $text)) <= $length) {
if (strlen((string) preg_replace('/<.*?>/', '', $text)) <= $length) {
return $text;
}
@@ -284,7 +284,7 @@ class Truncator
$truncate .= $line_matchings[1];
}
// calculate the length of the plain text part of the line; handle entities as one character
$content_length = strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', ' ', $line_matchings[2]));
$content_length = strlen((string) preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', ' ', $line_matchings[2]));
if ($total_length+$content_length> $length) {
// the number of characters which are left
$left = $length - $total_length;

View File

@@ -29,7 +29,7 @@ class YamlLinter
* @param string|null $folder
* @return array
*/
public static function lint(string $folder = null)
public static function lint(?string $folder = null)
{
if (null !== $folder) {
$folder = $folder ?: GRAV_ROOT;

View File

@@ -72,7 +72,7 @@ class Inflector
if (is_array(static::$uncountable)) {
foreach (static::$uncountable as $_uncountable) {
if (substr($lowercased_word, -1 * strlen($_uncountable)) === $_uncountable) {
if (substr($lowercased_word, -1 * strlen((string) $_uncountable)) === $_uncountable) {
return $word;
}
}
@@ -81,7 +81,7 @@ class Inflector
if (is_array(static::$irregular)) {
foreach (static::$irregular as $_plural => $_singular) {
if (preg_match('/(' . $_plural . ')$/i', $word, $arr)) {
return preg_replace('/(' . $_plural . ')$/i', substr($arr[0], 0, 1) . substr($_singular, 1), $word);
return preg_replace('/(' . $_plural . ')$/i', substr($arr[0], 0, 1) . substr((string) $_singular, 1), $word);
}
}
}
@@ -89,7 +89,7 @@ class Inflector
if (is_array(static::$plural)) {
foreach (static::$plural as $rule => $replacement) {
if (preg_match($rule, $word)) {
return preg_replace($rule, $replacement, $word);
return preg_replace($rule, (string) $replacement, $word);
}
}
}
@@ -117,7 +117,7 @@ class Inflector
if (is_array(static::$uncountable)) {
foreach (static::$uncountable as $_uncountable) {
if (substr($lowercased_word, -1 * strlen($_uncountable)) === $_uncountable) {
if (substr($lowercased_word, -1 * strlen((string) $_uncountable)) === $_uncountable) {
return $word;
}
}
@@ -126,7 +126,7 @@ class Inflector
if (is_array(static::$irregular)) {
foreach (static::$irregular as $_plural => $_singular) {
if (preg_match('/(' . $_singular . ')$/i', $word, $arr)) {
return preg_replace('/(' . $_singular . ')$/i', substr($arr[0], 0, 1) . substr($_plural, 1), $word);
return preg_replace('/(' . $_singular . ')$/i', substr($arr[0], 0, 1) . substr((string) $_plural, 1), $word);
}
}
}
@@ -134,7 +134,7 @@ class Inflector
if (is_array(static::$singular)) {
foreach (static::$singular as $rule => $replacement) {
if (preg_match($rule, $word)) {
return preg_replace($rule, $replacement, $word);
return preg_replace($rule, (string) $replacement, $word);
}
}
}
@@ -186,7 +186,7 @@ class Inflector
*/
public static function camelize($word)
{
return str_replace(' ', '', ucwords(preg_replace('/[^\p{L}^0-9]+/', ' ', $word)));
return str_replace(' ', '', ucwords((string) preg_replace('/[^\p{L}^0-9]+/', ' ', $word)));
}
/**
@@ -203,10 +203,10 @@ class Inflector
public static function underscorize($word)
{
$regex1 = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1_\2', $word);
$regex2 = preg_replace('/([a-zd])([A-Z])/', '\1_\2', $regex1);
$regex3 = preg_replace('/[^\p{L}^0-9]+/u', '_', $regex2);
$regex2 = preg_replace('/([a-zd])([A-Z])/', '\1_\2', (string) $regex1);
$regex3 = preg_replace('/[^\p{L}^0-9]+/u', '_', (string) $regex2);
return strtolower($regex3);
return strtolower((string) $regex3);
}
/**
@@ -223,11 +223,11 @@ class Inflector
public static function hyphenize($word)
{
$regex1 = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1-\2', $word);
$regex2 = preg_replace('/([a-z])([A-Z])/', '\1-\2', $regex1);
$regex3 = preg_replace('/([0-9])([A-Z])/', '\1-\2', $regex2);
$regex4 = preg_replace('/[^\p{L}^0-9]+/', '-', $regex3);
$regex2 = preg_replace('/([a-z])([A-Z])/', '\1-\2', (string) $regex1);
$regex3 = preg_replace('/([0-9])([A-Z])/', '\1-\2', (string) $regex2);
$regex4 = preg_replace('/[^\p{L}^0-9]+/', '-', (string) $regex3);
$regex4 = trim($regex4, '-');
$regex4 = trim((string) $regex4, '-');
return strtolower($regex4);
}
@@ -326,16 +326,12 @@ class Inflector
return $number . static::$ordinals['default'];
}
switch ($number % 10) {
case 1:
return $number . static::$ordinals['first'];
case 2:
return $number . static::$ordinals['second'];
case 3:
return $number . static::$ordinals['third'];
default:
return $number . static::$ordinals['default'];
}
return match ($number % 10) {
1 => $number . static::$ordinals['first'],
2 => $number . static::$ordinals['second'],
3 => $number . static::$ordinals['third'],
default => $number . static::$ordinals['default'],
};
}
/**

View File

@@ -24,7 +24,7 @@ use function is_object;
* Class Iterator
* @package Grav\Common
*/
class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable, \Stringable
{
use Constructor, ArrayAccessWithGetters, ArrayIterator, Countable, Serializable, Export;
@@ -35,11 +35,10 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
* Convert function calls for the existing keys into their values.
*
* @param string $key
* @param mixed $args
* @return mixed
*/
#[\ReturnTypeWillChange]
public function __call($key, $args)
public function __call($key, mixed $args)
{
return $this->items[$key] ?? null;
}
@@ -63,7 +62,7 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
* @return string
*/
#[\ReturnTypeWillChange]
public function __toString()
public function __toString(): string
{
return implode(',', $this->items);
}
@@ -143,7 +142,7 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
*
* @return string|int|false Key if found, otherwise false.
*/
public function indexOf($needle)
public function indexOf(mixed $needle)
{
foreach (array_values($this->items) as $key => $value) {
if ($value === $needle) {
@@ -230,7 +229,7 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
*
* @return $this
*/
public function filter(callable $callback = null)
public function filter(?callable $callback = null)
{
foreach ($this->items as $key => $value) {
if ((!$callback && !(bool)$value) || ($callback && !$callback($value, $key))) {
@@ -250,7 +249,7 @@ class Iterator implements \ArrayAccess, \Iterator, \Countable, \Serializable
* @return $this|array
*
*/
public function sort(callable $callback = null, $desc = false)
public function sort(?callable $callback = null, $desc = false)
{
if (!$callback || !is_callable($callback)) {
return $this;

View File

@@ -149,9 +149,7 @@ class Language
{
$languagesArray = $this->languages; //Make local copy
$languagesArray = array_map(static function ($value) use ($delimiter) {
return preg_quote($value, $delimiter);
}, $languagesArray);
$languagesArray = array_map(static fn($value) => preg_quote((string) $value, $delimiter), $languagesArray);
sort($languagesArray);
@@ -358,7 +356,7 @@ class Language
* @param bool $assoc Return values in ['en' => '.en.md', ...] format.
* @return array Key is the language code, value is the file extension to be used.
*/
public function getFallbackPageExtensions(string $fileExtension = null, string $languageCode = null, bool $assoc = false)
public function getFallbackPageExtensions(?string $fileExtension = null, ?string $languageCode = null, bool $assoc = false)
{
$fileExtension = $fileExtension ?: CONTENT_EXT;
$key = $fileExtension . '-' . ($languageCode ?? 'default') . '-' . (int)$assoc;
@@ -411,7 +409,7 @@ class Language
* @param bool $includeDefault If true, list contains '', which can be used for default
* @return array
*/
public function getFallbackLanguages(string $languageCode = null, bool $includeDefault = false)
public function getFallbackLanguages(?string $languageCode = null, bool $includeDefault = false)
{
// Handle default.
if ($languageCode === '' || !$this->enabled()) {
@@ -489,7 +487,7 @@ class Language
* @param bool $html_out
* @return string|string[]
*/
public function translate($args, array $languages = null, $array_support = false, $html_out = false)
public function translate($args, ?array $languages = null, $array_support = false, $html_out = false)
{
if (is_array($args)) {
$lookup = array_shift($args);
@@ -593,7 +591,7 @@ class Language
*/
public function getBrowserLanguages($accept_langs = [])
{
user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, no longer used', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, no longer used', E_USER_DEPRECATED);
if (empty($this->http_accept_language)) {
if (empty($accept_langs) && isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
@@ -604,7 +602,7 @@ class Language
$langs = [];
foreach (explode(',', $accept_langs) as $k => $pref) {
foreach (explode(',', (string) $accept_langs) as $k => $pref) {
// split $pref again by ';q='
// and decorate the language entries by inverted position
if (false !== ($i = strpos($pref, ';q='))) {

View File

@@ -35,7 +35,7 @@ class Parsedown extends \Parsedown
$defaults = ['markdown' => $defaults];
}
$excerpts = new Excerpts($excerpts, $defaults);
user_error(__CLASS__ . '::' . __FUNCTION__ . '($page, $defaults) is deprecated since Grav 1.6.10, use new ' . __CLASS__ . '(new ' . Excerpts::class . '($page, [\'markdown\' => $defaults])) instead.', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '($page, $defaults) is deprecated since Grav 1.6.10, use new ' . self::class . '(new ' . Excerpts::class . '($page, [\'markdown\' => $defaults])) instead.', E_USER_DEPRECATED);
}
$this->init($excerpts, $defaults);

View File

@@ -36,7 +36,7 @@ class ParsedownExtra extends \ParsedownExtra
$defaults = ['markdown' => $defaults];
}
$excerpts = new Excerpts($excerpts, $defaults);
user_error(__CLASS__ . '::' . __FUNCTION__ . '($page, $defaults) is deprecated since Grav 1.6.10, use new ' . __CLASS__ . '(new ' . Excerpts::class . '($page, [\'markdown\' => $defaults])) instead.', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '($page, $defaults) is deprecated since Grav 1.6.10, use new ' . self::class . '(new ' . Excerpts::class . '($page, [\'markdown\' => $defaults])) instead.', E_USER_DEPRECATED);
}
parent::__construct();

View File

@@ -49,7 +49,7 @@ trait ParsedownGravTrait
$defaults = ['markdown' => $defaults];
}
$this->excerpts = new Excerpts($excerpts, $defaults);
user_error(__CLASS__ . '::' . __FUNCTION__ . '($page, $defaults) is deprecated since Grav 1.6.10, use ->init(new ' . Excerpts::class . '($page, [\'markdown\' => $defaults])) instead.', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '($page, $defaults) is deprecated since Grav 1.6.10, use ->init(new ' . Excerpts::class . '($page, [\'markdown\' => $defaults])) instead.', E_USER_DEPRECATED);
} else {
$this->excerpts = $excerpts;
}
@@ -133,7 +133,7 @@ trait ParsedownGravTrait
array_splice($this->InlineTypes[$type], $index, 0, [$tag]);
}
if (strpos($this->inlineMarkerList, $type) === false) {
if (!str_contains($this->inlineMarkerList, $type)) {
$this->inlineMarkerList .= $type;
}
}
@@ -199,7 +199,7 @@ trait ParsedownGravTrait
*/
protected function blockTwigTag($line)
{
if (preg_match('/(?:{{|{%|{#)(.*)(?:}}|%}|#})/', $line['body'], $matches)) {
if (preg_match('/(?:{{|{%|{#)(.*)(?:}}|%}|#})/', (string) $line['body'], $matches)) {
return ['markup' => $line['body']];
}
@@ -212,7 +212,7 @@ trait ParsedownGravTrait
*/
protected function inlineSpecialCharacter($excerpt)
{
if ($excerpt['text'][0] === '&' && !preg_match('/^&#?\w+;/', $excerpt['text'])) {
if ($excerpt['text'][0] === '&' && !preg_match('/^&#?\w+;/', (string) $excerpt['text'])) {
return [
'markup' => '&amp;',
'extent' => 1,
@@ -235,7 +235,7 @@ trait ParsedownGravTrait
*/
protected function inlineImage($excerpt)
{
if (preg_match($this->twig_link_regex, $excerpt['text'], $matches)) {
if (preg_match($this->twig_link_regex, (string) $excerpt['text'], $matches)) {
$excerpt['text'] = str_replace($matches[1], '/', $excerpt['text']);
$excerpt = parent::inlineImage($excerpt);
$excerpt['element']['attributes']['src'] = $matches[1];
@@ -264,7 +264,7 @@ trait ParsedownGravTrait
$type = $excerpt['type'] ?? 'link';
// do some trickery to get around Parsedown requirement for valid URL if its Twig in there
if (preg_match($this->twig_link_regex, $excerpt['text'], $matches)) {
if (preg_match($this->twig_link_regex, (string) $excerpt['text'], $matches)) {
$excerpt['text'] = str_replace($matches[1], '/', $excerpt['text']);
$excerpt = parent::inlineLink($excerpt);
$excerpt['element']['attributes']['href'] = $matches[1];

View File

@@ -105,7 +105,7 @@ interface MediaCollectionInterface extends \Grav\Framework\Media\Interfaces\Medi
* @param Blueprint|null $blueprint
* @return Medium|null
*/
public function createFromArray(array $items = [], Blueprint $blueprint = null);
public function createFromArray(array $items = [], ?Blueprint $blueprint = null);
/**
* @param MediaObjectInterface $mediaObject

View File

@@ -207,11 +207,10 @@ interface MediaObjectInterface extends \Grav\Framework\Media\Interfaces\MediaObj
* Allow any action to be called on this medium from twig or markdown
*
* @param string $method
* @param mixed $args
* @return $this
*/
#[\ReturnTypeWillChange]
public function __call($method, $args);
public function __call($method, mixed $args);
/**
* Set value by using dot notation for nested arrays/objects.
@@ -223,5 +222,5 @@ interface MediaObjectInterface extends \Grav\Framework\Media\Interfaces\MediaObj
* @param string|null $separator Separator, defaults to '.'
* @return $this
*/
public function set($name, $value, $separator = null);
public function set($name, mixed $value, $separator = null);
}

View File

@@ -32,7 +32,7 @@ interface MediaUploadInterface
* @return string
* @throws RuntimeException
*/
public function checkUploadedFile(UploadedFileInterface $uploadedFile, string $filename = null, array $settings = null): string;
public function checkUploadedFile(UploadedFileInterface $uploadedFile, ?string $filename = null, ?array $settings = null): string;
/**
* Copy uploaded file to the media collection.
@@ -51,7 +51,7 @@ interface MediaUploadInterface
* @return void
* @throws RuntimeException
*/
public function copyUploadedFile(UploadedFileInterface $uploadedFile, string $filename, array $settings = null): void;
public function copyUploadedFile(UploadedFileInterface $uploadedFile, string $filename, ?array $settings = null): void;
/**
* Delete real file from the media collection.
@@ -60,7 +60,7 @@ interface MediaUploadInterface
* @param array|null $settings
* @return void
*/
public function deleteFile(string $filename, array $settings = null): void;
public function deleteFile(string $filename, ?array $settings = null): void;
/**
* Rename file inside the media collection.
@@ -69,5 +69,5 @@ interface MediaUploadInterface
* @param string $to
* @param array|null $settings
*/
public function renameFile(string $from, string $to, array $settings = null): void;
public function renameFile(string $from, string $to, ?array $settings = null): void;
}

View File

@@ -97,7 +97,7 @@ trait ImageMediaTrait
}
$basename = $this->get('basename');
if (preg_match('/[a-z0-9]{40}-(.*)/', $basename, $matches)) {
if (preg_match('/[a-z0-9]{40}-(.*)/', (string) $basename, $matches)) {
$basename = $matches[1];
}
return $basename;

View File

@@ -88,7 +88,7 @@ trait MediaFileTrait
}
$path = $this->path(false);
$output = preg_replace('|^' . preg_quote(GRAV_ROOT, '|') . '|', '', $path) ?: $path;
$output = preg_replace('|^' . preg_quote(GRAV_ROOT, '|') . '|', '', (string) $path) ?: $path;
/** @var UniformResourceLocator $locator */
$locator = $this->getGrav()['locator'];

View File

@@ -182,7 +182,7 @@ trait MediaObjectTrait
// join the strings
$querystring = implode('&', $this->medium_querystring);
// explode all strings
$query_parts = explode('&', $querystring);
$query_parts = explode('&', (string) $querystring);
// Join them again now ensure the elements are unique
$querystring = implode('&', array_unique($query_parts));
@@ -598,7 +598,7 @@ trait MediaObjectTrait
* @param string|null $separator Separator, defaults to '.'
* @return mixed Value.
*/
abstract public function get($name, $default = null, $separator = null);
abstract public function get($name, mixed $default = null, $separator = null);
/**
* Set value by using dot notation for nested arrays/objects.
@@ -610,7 +610,7 @@ trait MediaObjectTrait
* @param string|null $separator Separator, defaults to '.'
* @return $this
*/
abstract public function set($name, $value, $separator = null);
abstract public function set($name, mixed $value, $separator = null);
/**
* @param string $thumb

View File

@@ -57,15 +57,15 @@ trait MediaTrait
return null;
}
if (strpos($folder, '://')) {
if (strpos((string) $folder, '://')) {
return $folder;
}
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
$user = $locator->findResource('user://');
if (strpos($folder, $user) === 0) {
return 'user://' . substr($folder, strlen($user)+1);
if (str_starts_with((string) $folder, $user)) {
return 'user://' . substr((string) $folder, strlen($user)+1);
}
return null;

View File

@@ -71,7 +71,7 @@ trait MediaUploadTrait
* @return string
* @throws RuntimeException
*/
public function checkUploadedFile(UploadedFileInterface $uploadedFile, string $filename = null, array $settings = null): string
public function checkUploadedFile(UploadedFileInterface $uploadedFile, ?string $filename = null, ?array $settings = null): string
{
// Check if there is an upload error.
switch ($uploadedFile->getError()) {
@@ -115,7 +115,7 @@ trait MediaUploadTrait
* @return string
* @throws RuntimeException
*/
public function checkFileMetadata(array $metadata, string $filename = null, array $settings = null): string
public function checkFileMetadata(array $metadata, ?string $filename = null, ?array $settings = null): string
{
// Add the defaults to the settings.
$settings = $this->getUploadSettings($settings);
@@ -206,11 +206,11 @@ trait MediaUploadTrait
break;
}
$isMime = strstr($type, '/');
$isMime = strstr((string) $type, '/');
$find = str_replace(['.', '*', '+'], ['\.', '.*', '\+'], $type);
if ($isMime) {
$match = preg_match('#' . $find . '$#', $mime);
$match = preg_match('#' . $find . '$#', (string) $mime);
if (!$match) {
// TODO: translate
$errors[] = 'The MIME type "' . $mime . '" for the file "' . $filepath . '" is not an accepted.';
@@ -219,7 +219,7 @@ trait MediaUploadTrait
break;
}
} else {
$match = preg_match('#' . $find . '$#', $filename);
$match = preg_match('#' . $find . '$#', (string) $filename);
if (!$match) {
// TODO: translate
$errors[] = 'The File Extension for the file "' . $filepath . '" is not an accepted.';
@@ -252,7 +252,7 @@ trait MediaUploadTrait
* @return void
* @throws RuntimeException
*/
public function copyUploadedFile(UploadedFileInterface $uploadedFile, string $filename, array $settings = null): void
public function copyUploadedFile(UploadedFileInterface $uploadedFile, string $filename, ?array $settings = null): void
{
// Add the defaults to the settings.
$settings = $this->getUploadSettings($settings);
@@ -286,7 +286,7 @@ trait MediaUploadTrait
if ($uploadedFile->getError() === \UPLOAD_ERR_OK) {
// Move uploaded file.
$this->doMoveUploadedFile($uploadedFile, $filename, $path);
} elseif (strpos($filename, 'original/') === 0 && !$this->fileExists($filename, $path) && $this->fileExists($basename, $path)) {
} elseif (str_starts_with($filename, 'original/') && !$this->fileExists($filename, $path) && $this->fileExists($basename, $path)) {
// Original image support: override original image if it's the same as the uploaded image.
$this->doCopy($basename, $filename, $path);
}
@@ -329,7 +329,7 @@ trait MediaUploadTrait
* @return void
* @throws RuntimeException
*/
public function deleteFile(string $filename, array $settings = null): void
public function deleteFile(string $filename, ?array $settings = null): void
{
// Add the defaults to the settings.
$settings = $this->getUploadSettings($settings);
@@ -371,7 +371,7 @@ trait MediaUploadTrait
* @param string $to
* @param array|null $settings
*/
public function renameFile(string $from, string $to, array $settings = null): void
public function renameFile(string $from, string $to, ?array $settings = null): void
{
// Add the defaults to the settings.
$settings = $this->getUploadSettings($settings);
@@ -558,7 +558,7 @@ trait MediaUploadTrait
$fileParts = (array)$filesystem->pathinfo($filename);
foreach ($dir as $file) {
$preg_name = preg_quote($fileParts['filename'], '`');
$preg_name = preg_quote((string) $fileParts['filename'], '`');
$preg_ext = preg_quote($fileParts['extension'] ?? '.', '`');
$preg_filename = preg_quote($basename, '`');

View File

@@ -138,7 +138,7 @@ trait ThumbnailMediaTrait
$closure = [$parent, $method];
if (!is_callable($closure)) {
throw new BadMethodCallException(get_class($parent) . '::' . $method . '() not found.');
throw new BadMethodCallException($parent::class . '::' . $method . '() not found.');
}
return $closure(...$arguments);

View File

@@ -43,7 +43,7 @@ class Collection extends Iterator implements PageCollectionInterface
* @param array $params
* @param Pages|null $pages
*/
public function __construct($items = [], array $params = [], Pages $pages = null)
public function __construct($items = [], array $params = [], ?Pages $pages = null)
{
parent::__construct($items);
@@ -139,9 +139,7 @@ class Collection extends Iterator implements PageCollectionInterface
$array1 = $this->items;
$array2 = $collection->toArray();
$this->items = array_uintersect($array1, $array2, function ($val1, $val2) {
return strcmp($val1['slug'], $val2['slug']);
});
$this->items = array_uintersect($array1, $array2, fn($val1, $val2) => strcmp((string) $val1['slug'], (string) $val2['slug']));
return $this;
}
@@ -357,7 +355,7 @@ class Collection extends Iterator implements PageCollectionInterface
continue;
}
$date = $field ? strtotime($page->value($field)) : $page->date();
$date = $field ? strtotime((string) $page->value($field)) : $page->date();
if ((!$start || $date >= $start) && (!$end || $date <= $end)) {
$date_range[$path] = $slug;

View File

@@ -46,7 +46,7 @@ interface PageCollectionInterface extends Traversable, ArrayAccess, Countable, S
* Add a single page to a collection
*
* @param PageInterface $page
* @return $this
* @return $this|PageCollectionInterface<TKey,T>
*/
public function addPage(PageInterface $page);
@@ -63,7 +63,7 @@ interface PageCollectionInterface extends Traversable, ArrayAccess, Countable, S
*
* Create a copy of this collection
*
* @return static
* @return static<TKey,T>
*/
public function copy();

View File

@@ -43,9 +43,8 @@ interface PageLegacyInterface
* Modify a header value directly
*
* @param string $key
* @param mixed $value
*/
public function modifyHeader($key, $value);
public function modifyHeader($key, mixed $value);
/**
* @return int
@@ -68,9 +67,8 @@ interface PageLegacyInterface
* Add an entry to the page's contentMeta array
*
* @param string $name
* @param mixed $value
*/
public function addContentMeta($name, $value);
public function addContentMeta($name, mixed $value);
/**
* Return the whole contentMeta array as it currently stands

View File

@@ -133,7 +133,7 @@ interface PageRoutableInterface
* @param PageInterface|null $var the parent page object
* @return PageInterface|null the parent page object if it exists.
*/
public function parent(PageInterface $var = null);
public function parent(?PageInterface $var = null);
/**
* Gets the top parent object for this page. Can return page itself.

View File

@@ -52,5 +52,5 @@ interface PagesSourceInterface // extends \Iterator
* @param array|null $options
* @return array
*/
public function getChildren(string $route, array $options = null): array;
public function getChildren(string $route, ?array $options = null): array;
}

View File

@@ -42,14 +42,14 @@ class Excerpts
* @param PageInterface|null $page
* @param array|null $config
*/
public function __construct(PageInterface $page = null, array $config = null)
public function __construct(?PageInterface $page = null, ?array $config = null)
{
$this->page = $page ?? Grav::instance()['page'] ?? null;
// Add defaults to the configuration.
if (null === $config || !isset($config['markdown'], $config['images'])) {
$c = Grav::instance()['config'];
$config = $config ?? [];
$config ??= [];
$config += [
'markdown' => $c->get('system.pages.markdown', []),
'images' => $c->get('system.images', [])
@@ -96,13 +96,13 @@ class Excerpts
public function processLinkExcerpt(array $excerpt, string $type = 'link'): array
{
$grav = Grav::instance();
$url = htmlspecialchars_decode(rawurldecode($excerpt['element']['attributes']['href']));
$url = htmlspecialchars_decode(rawurldecode((string) $excerpt['element']['attributes']['href']));
$url_parts = $this->parseUrl($url);
// If there is a query, then parse it and build action calls.
if (isset($url_parts['query'])) {
$actions = array_reduce(
explode('&', $url_parts['query']),
explode('&', (string) $url_parts['query']),
static function ($carry, $item) {
$parts = explode('=', $item, 2);
$value = isset($parts[1]) ? rawurldecode($parts[1]) : true;
@@ -119,7 +119,7 @@ class Excerpts
$skip = [];
// Unless told to not process, go through actions.
if (array_key_exists('noprocess', $actions)) {
$skip = is_bool($actions['noprocess']) ? $actions : explode(',', $actions['noprocess']);
$skip = is_bool($actions['noprocess']) ? $actions : explode(',', (string) $actions['noprocess']);
unset($actions['noprocess']);
}
@@ -185,7 +185,7 @@ class Excerpts
*/
public function processImageExcerpt(array $excerpt): array
{
$url = htmlspecialchars_decode(urldecode($excerpt['element']['attributes']['src']));
$url = htmlspecialchars_decode(urldecode((string) $excerpt['element']['attributes']['src']));
$url_parts = $this->parseUrl($url);
$media = null;
@@ -207,7 +207,7 @@ class Excerpts
if ($local_file) {
$filename = Utils::basename($url_parts['path']);
$folder = dirname($url_parts['path']);
$folder = dirname((string) $url_parts['path']);
// Get the local path to page media if possible.
if ($this->page && $folder === $this->page->url(false, false, false)) {
@@ -268,7 +268,7 @@ class Excerpts
// if there is a query, then parse it and build action calls
if (isset($url_parts['query'])) {
$actions = array_reduce(
explode('&', $url_parts['query']),
explode('&', (string) $url_parts['query']),
static function ($carry, $item) {
$parts = explode('=', $item, 2);
$value = $parts[1] ?? null;
@@ -296,10 +296,10 @@ class Excerpts
foreach ($actions as $action) {
$matches = [];
if (preg_match('/\[(.*)\]/', $action['params'], $matches)) {
if (preg_match('/\[(.*)\]/', (string) $action['params'], $matches)) {
$args = [explode(',', $matches[1])];
} else {
$args = explode(',', $action['params']);
$args = explode(',', (string) $action['params']);
}
$medium = call_user_func_array([$medium, $action['method']], $args);

View File

@@ -38,7 +38,7 @@ class Media extends AbstractMedia
* @param array|null $media_order
* @param bool $load
*/
public function __construct($path, array $media_order = null, $load = true)
public function __construct($path, ?array $media_order = null, $load = true)
{
$this->setPath($path);
$this->media_order = $media_order;
@@ -152,14 +152,14 @@ class Media extends AbstractMedia
foreach ($iterator as $file => $info) {
// Ignore folders and Markdown files.
$filename = $info->getFilename();
if (!$info->isFile() || $info->getExtension() === 'md' || $filename === 'frontmatter.yaml' || $filename === 'media.json' || strpos($filename, '.') === 0) {
if (!$info->isFile() || $info->getExtension() === 'md' || $filename === 'frontmatter.yaml' || $filename === 'media.json' || str_starts_with($filename, '.')) {
continue;
}
// Find out what type we're dealing with
[$basename, $ext, $type, $extra] = $this->getFileParts($filename);
if (!in_array(strtolower($ext), $media_types, true)) {
if (!in_array(strtolower((string) $ext), $media_types, true)) {
continue;
}

View File

@@ -229,7 +229,7 @@ abstract class AbstractMedia implements ExportInterface, MediaCollectionInterfac
* @param Blueprint|null $blueprint
* @return Medium|null
*/
public function createFromArray(array $items = [], Blueprint $blueprint = null)
public function createFromArray(array $items = [], ?Blueprint $blueprint = null)
{
return MediumFactory::fromArray($items, $blueprint);
}

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