From 80be13743f18db5ff4bf22bd6f485eebcfef86fe Mon Sep 17 00:00:00 2001 From: ouidade Date: Fri, 19 Mar 2021 16:07:04 +0100 Subject: [PATCH] test appel img twig --- .github/workflows/build.yaml | 66 ---- .github/workflows/tests.yaml | 72 ---- CHANGELOG.md | 30 +- README.md | 175 +++++++-- SECURITY.md | 8 +- composer.json | 8 +- composer.lock | 349 +++++++++--------- system/blueprints/config/system.yaml | 59 ++- system/blueprints/flex/pages.yaml | 2 +- system/config/system.yaml | 7 +- system/defines.php | 2 +- system/src/Grav/Common/Assets/BaseAsset.php | 26 ++ system/src/Grav/Common/Assets/Css.php | 2 +- system/src/Grav/Common/Assets/Js.php | 2 +- system/src/Grav/Common/Assets/Pipeline.php | 5 +- system/src/Grav/Common/Cache.php | 6 +- .../Common/Flex/Types/Pages/PageIndex.php | 47 ++- .../Common/Flex/Types/Pages/PageObject.php | 52 ++- .../Flex/Types/Pages/Storage/PageStorage.php | 29 +- .../Types/Pages/Traits/PageTranslateTrait.php | 2 +- system/src/Grav/Common/Grav.php | 18 +- system/src/Grav/Common/Helpers/LogViewer.php | 8 +- .../Page/Interfaces/PageRoutableInterface.php | 2 +- .../Grav/Common/Page/Markdown/Excerpts.php | 4 +- system/src/Grav/Common/Page/Page.php | 2 +- system/src/Grav/Common/Page/Pages.php | 38 +- system/src/Grav/Common/Page/Types.php | 34 +- system/src/Grav/Common/Plugin.php | 87 +++-- system/src/Grav/Common/Plugins.php | 38 +- .../Common/Processors/InitializeProcessor.php | 9 +- .../Common/Service/PagesServiceProvider.php | 58 +-- system/src/Grav/Common/Theme.php | 50 +-- system/src/Grav/Common/Themes.php | 21 +- system/src/Grav/Common/Uri.php | 15 +- system/src/Grav/Console/Cli/CleanCommand.php | 5 +- .../Traits/ControllerResponseTrait.php | 51 +++ system/src/Grav/Framework/Flex/FlexIndex.php | 2 +- system/src/Grav/Framework/Flex/FlexObject.php | 8 + .../Framework/Flex/Pages/FlexPageObject.php | 58 ++- .../Flex/Pages/Traits/PageAuthorsTrait.php | 18 +- .../Flex/Pages/Traits/PageLegacyTrait.php | 22 +- .../Flex/Pages/Traits/PageRoutableTrait.php | 24 +- .../Storage/AbstractFilesystemStorage.php | 4 +- .../Framework/Flex/Storage/FileStorage.php | 2 + .../Framework/Flex/Storage/FolderStorage.php | 73 ++-- .../Framework/Flex/Storage/SimpleStorage.php | 10 +- .../index.yaml | 87 ----- .../index.yaml | 29 -- .../index.yaml | 50 --- .../index.yaml | 107 ------ .../index.yaml | 53 --- .../index.yaml | 31 -- .../index.yaml | 84 ----- .../index.yaml | 29 -- .../index.yaml | 31 -- user/blueprints/pages/modular/programmes.yaml | 3 - user/config/site.yaml | 6 +- user/config/system.yaml | 17 +- ...{Europan France.jpg => europan_france.jpg} | Bin ...O_moinsde6cm_sscartouche.png => popsu.png} | Bin .../01.home/02._programmes/programmes.md | 13 +- .../02._equipe-epau/personnes.md | 3 +- .../templates/modular/programmes.html.twig | 13 +- 63 files changed, 999 insertions(+), 1167 deletions(-) delete mode 100644 .github/workflows/build.yaml delete mode 100644 .github/workflows/tests.yaml delete mode 100644 tmp/forms/fg86637jgl2sbvcbloavimfam4/73f35c84f67d9518064f6783910db89a/index.yaml delete mode 100644 tmp/forms/fg86637jgl2sbvcbloavimfam4/ae2c7e0ffb4b4b1c4654412e6429a17c/index.yaml delete mode 100644 tmp/forms/fg86637jgl2sbvcbloavimfam4/b24e06058e6bf2c3e455378b84824a00/index.yaml delete mode 100644 tmp/forms/hajnagponl11621ppdikc5e6g4/c5c66e69061fcfcc38c77e522e153efe/index.yaml delete mode 100644 tmp/forms/m8co5qkkf12uur4tra88dbie5t/cdb3ae30b3dab66b186228ae772dd1a0/index.yaml delete mode 100644 tmp/forms/m8co5qkkf12uur4tra88dbie5t/e75346bd00d0b9954ac33c8fde35d73f/index.yaml delete mode 100644 tmp/forms/oocdaafg1m81alcgel4g63t6cs/a44b13d8025f9fb13b03184c68bd181f/index.yaml delete mode 100644 tmp/forms/oocdaafg1m81alcgel4g63t6cs/e2b1fd25908ccd5d1621269a6a54fa1b/index.yaml delete mode 100644 tmp/forms/oocdaafg1m81alcgel4g63t6cs/f8b847bb606447afa42e342e90a112bf/index.yaml rename user/pages/01.home/02._programmes/{Europan France.jpg => europan_france.jpg} (100%) rename user/pages/01.home/02._programmes/{POPSU2018_LOGO_moinsde6cm_sscartouche.png => popsu.png} (100%) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml deleted file mode 100644 index 6f9d9b2..0000000 --- a/.github/workflows/build.yaml +++ /dev/null @@ -1,66 +0,0 @@ -name: Release Builds - -on: - release: - types: [published] - -jobs: - build: - if: "!github.event.release.prerelease" - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: 7.3 - extensions: opcache, gd - coverage: none - env: - COMPOSER_TOKEN: ${{ secrets.GLOBAL_TOKEN }} - - - name: Install Dependencies - run: | - sudo apt-get -y update -qq < /dev/null > /dev/null - sudo apt-get -y install -qq git zip < /dev/null > /dev/null - - - 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 - - # Development Local URL - # curl ${{ secrets.BUILD_SCRIPT_URL }} --output build-grav.sh - - - name: Grav Builder - run: | - bash ./build-grav.sh - - - name: Upload Grav Release Assets - id: upload-release-asset - uses: alexellis/upload-assets@0.2.3 - env: - GITHUB_TOKEN: ${{ secrets.GLOBAL_TOKEN }} - with: - asset_paths: '["./grav-dist/*.zip"]' - - slack: - name: Slack - needs: build - runs-on: ubuntu-latest - if: always() - steps: - - uses: technote-space/workflow-conclusion-action@v2 - - uses: 8398a7/action-slack@v3 - with: - status: failure - fields: repo,message,author,action - icon_emoji: ':octocat:' - author_name: 'Github Action Build' - text: '🚚 Automated Build Failure' - env: - GITHUB_TOKEN: ${{ secrets.GLOBAL_TOKEN }} - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - if: env.WORKFLOW_CONCLUSION == 'failure' diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml deleted file mode 100644 index e83e0c4..0000000 --- a/.github/workflows/tests.yaml +++ /dev/null @@ -1,72 +0,0 @@ -name: PHP Tests - -on: - push: - branches: [ develop ] - pull_request: - branches: [ develop ] - -jobs: - - unit-tests: - - runs-on: ${{ matrix.os }} - - strategy: - matrix: - php: [ 8.0, 7.4, 7.3] - os: [ubuntu-latest] - - steps: - - uses: actions/checkout@v2 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - extensions: opcache, gd - coverage: none - env: - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} - -# - name: Update composer -# run: composer update -# -# - name: Validate composer.json and composer.lock -# run: composer validate - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- - - - name: Install dependencies - run: composer install --prefer-dist --no-progress - - - name: Run test suite - run: vendor/bin/codecept run - -# slack: -# name: Slack -# needs: unit-tests -# runs-on: ubuntu-latest -# if: always() -# steps: -# - uses: technote-space/workflow-conclusion-action@v2 -# - uses: 8398a7/action-slack@v3 -# with: -# status: failure -# fields: repo,message,author,action -# icon_emoji: ':octocat:' -# author_name: 'Github Action Tests' -# text: '💥 Automated Test Failure' -# env: -# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -# SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} -# if: env.WORKFLOW_CONCLUSION == 'failure' diff --git a/CHANGELOG.md b/CHANGELOG.md index ef8e4fe..5fcd4bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,36 @@ +# v1.7.8 +## 03/17/2021 + +1. [](#new) + * Added `ControllerResponseTrait::createDownloadResponse()` method + * Added full blueprint support to theme if you move existing files in `blueprints/` to `blueprints/pages/` folder [#3255](https://github.com/getgrav/grav/issues/3255) + * Added support for `Theme::getFormFieldTypes()` just like in plugins +1. [](#improved) + * Optimized `Flex Pages` for speed + * Optimized saving visible/ordered pages when there are a lot of siblings [#3231](https://github.com/getgrav/grav/issues/3231) + * Clearing cache now deletes all clockwork files + * Improved `system.pages.redirect_default_route` and `system.pages.redirect_trailing_slash` configuration options to accept redirect code +1. [](#bugfix) + * Fixed clockwork error when clearing cache + * Fixed missing method `translated()` in `Flex Pages` + * Fixed missing `Flex Pages` in site if multi-language support has been enabled + * Fixed Grav using blueprints and form fields from disabled plugins + * Fixed `FlexIndex::sortBy(['key' => 'ASC'])` having no effect + * Fixed default Flex Pages collection ordering to order by filesystem path + * Fixed disappearing pages on save if `pages://` stream resolves to multiple folders where the preferred folder doesn't exist + * Fixed Markdown image attribute `loading` [#3251](https://github.com/getgrav/grav/pull/3251) + * Fixed `Uri::isValidExtension()` returning false positives + * Fixed `page.html` returning duplicated content with `system.pages.redirect_default_route` turned on [#3130](https://github.com/getgrav/grav/issues/3130) + * Fixed site redirect with redirect code failing when redirecting to sub-pages [#3035](https://github.com/getgrav/grav/pull/3035/files) + * Fixed `Uncaught ValueError: Path cannot be empty` when failing to upload a file [#3265](https://github.com/getgrav/grav/issues/3265) + * Fixed `Path cannot be empty` when viewing non-existent log file [#3270](https://github.com/getgrav/grav/issues/3270) + * Fixed `onAdminSave` original page having empty header [#3259](https://github.com/getgrav/grav/issues/3259) + # v1.7.7 ## 02/23/2021 1. [](#new) - * Added `Utils::arrayToQueryParams()` to convert an array into query params + * Added `Utils::arrayToQueryParams()` to convert an array into query params 1. [](#improved) * Added original image support for all flex objects and media fields * Improved `Pagination` class to allow custom pagination query parameter diff --git a/README.md b/README.md index 6c0fe00..562349f 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,150 @@ +# ![](https://avatars1.githubusercontent.com/u/8237355?v=2&s=50) Grav -# EPAU REad ME +[![PHPStan](https://img.shields.io/badge/PHPStan-enabled-brightgreen.svg?style=flat)](https://github.com/phpstan/phpstan) +[![SensioLabsInsight](https://insight.sensiolabs.com/projects/cfd20465-d0f8-4a0a-8444-467f5b5f16ad/mini.png)](https://insight.sensiolabs.com/projects/cfd20465-d0f8-4a0a-8444-467f5b5f16ad) +[![Discord](https://img.shields.io/discord/501836936584101899.svg?logo=discord&colorB=728ADA&label=Discord%20Chat)](https://chat.getgrav.org) + [![PHP Tests](https://github.com/getgrav/grav/workflows/PHP%20Tests/badge.svg?branch=develop)](https://github.com/getgrav/grav/actions?query=workflow%3A%22PHP+Tests%22) [![OpenCollective](https://opencollective.com/grav/backers/badge.svg)](#backers) [![OpenCollective](https://opencollective.com/grav/sponsors/badge.svg)](#sponsors) + +Grav is a **Fast**, **Simple**, and **Flexible**, file-based Web-platform. There is **Zero** installation required. Just extract the ZIP archive, and you are already up and running. It follows similar principles to other flat-file CMS platforms, but has a different design philosophy than most. Grav comes with a powerful **Package Management System** to allow for simple installation and upgrading of plugins and themes, as well as simple updating of Grav itself. + +The underlying architecture of Grav is designed to use well-established and _best-in-class_ technologies to ensure that Grav is simple to use and easy to extend. Some of these key technologies include: + +* [Twig Templating](https://twig.sensiolabs.org/): for powerful control of the user interface +* [Markdown](https://en.wikipedia.org/wiki/Markdown): for easy content creation +* [YAML](https://yaml.org): for simple configuration +* [Parsedown](https://parsedown.org/): for fast Markdown and Markdown Extra support +* [Doctrine Cache](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/caching.html): layer for performance +* [Pimple Dependency Injection Container](https://pimple.sensiolabs.org/): for extensibility and maintainability +* [Symfony Event Dispatcher](https://symfony.com/doc/current/components/event_dispatcher/introduction.html): for plugin event handling +* [Symfony Console](https://symfony.com/doc/current/components/console/introduction.html): for CLI interface +* [Gregwar Image Library](https://github.com/Gregwar/Image): for dynamic image manipulation + +# Requirements + +- PHP 7.3.6 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 + +The full documentation can be found from [learn.getgrav.org](https://learn.getgrav.org). + +# QuickStart + +These are the options to get Grav: + +### Downloading a Grav Package + +You can download a **ready-built** package from the [Downloads page on https://getgrav.org](https://getgrav.org/downloads) + +### With Composer + +You can create a new project with the latest **stable** Grav release with the following command: + +``` +$ composer create-project getgrav/grav ~/webroot/grav +``` + +### From GitHub + +1. Clone the Grav repository from [https://github.com/getgrav/grav]() to a folder in the webroot of your server, e.g. `~/webroot/grav`. Launch a **terminal** or **console** and navigate to the webroot folder: + ``` + $ cd ~/webroot + $ git clone https://github.com/getgrav/grav.git + ``` + +2. Install the **plugin** and **theme dependencies** by using the [Grav CLI application](https://learn.getgrav.org/advanced/grav-cli) `bin/grav`: + ``` + $ cd ~/webroot/grav + $ bin/grav install + ``` + +Check out the [install procedures](https://learn.getgrav.org/basics/installation) for more information. + +# Adding Functionality + +You can download [plugins](https://getgrav.org/downloads/plugins) or [themes](https://getgrav.org/downloads/themes) manually from the appropriate tab on the [Downloads page on https://getgrav.org](https://getgrav.org/downloads), but the preferred solution is to use the [Grav Package Manager](https://learn.getgrav.org/advanced/grav-gpm) or `GPM`: + +``` +$ bin/gpm index +``` + +This will display all the available plugins and then you can install one or more with: + +``` +$ bin/gpm install +``` + +# Updating + +To update Grav you should use the [Grav Package Manager](https://learn.getgrav.org/advanced/grav-gpm) or `GPM`: + +``` +$ bin/gpm selfupgrade +``` + +To update plugins and themes: + +``` +$ bin/gpm update +``` + +## Upgrading from older version + +* [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) + +# 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. + +## Security issues +If you discover a possible security issue related to Grav or one of its plugins, please email the core team at contact@getgrav.org and we'll address it as soon as possible. + +# Getting Started + +* [What is Grav?](https://learn.getgrav.org/basics/what-is-grav) +* [Install](https://learn.getgrav.org/basics/installation) Grav in few seconds +* Understand the [Configuration](https://learn.getgrav.org/basics/grav-configuration) +* Take a peek at our available free [Skeletons](https://getgrav.org/downloads/skeletons) +* If you have questions, jump on our [Discord Chat Server](https://chat.getgrav.org)! +* Have fun! + +# Exploring More + +* Have a look at our [Basic Tutorial](https://learn.getgrav.org/basics/basic-tutorial) +* Dive into more [advanced](https://learn.getgrav.org/advanced) functions +* Learn about the [Grav CLI](https://learn.getgrav.org/cli-console/grav-cli) +* Review examples in the [Grav Cookbook](https://learn.getgrav.org/cookbook) +* More [Awesome Grav Stuff](https://github.com/getgrav/awesome-grav) + +# Backers +Support Grav with a monthly donation to help us continue development. [[Become a backer](https://opencollective.com/grav#backer)] + + + +# Sponsors +Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/grav#sponsor)] + + + +# License + +See [LICENSE](LICENSE.txt) - - intall grav avec composer +[gitflow-model]: http://nvie.com/posts/a-successful-git-branching-model/ +[gitflow-extensions]: https://github.com/nvie/gitflow - ```composer create-project getgrav/grav ~/webroot/grav``` +# Running Tests - - lance serveur local +First install the dev dependencies by running `composer install` from the Grav root. - ```cd ~/webroot/nomdusite``` - ```php -S localhost:8000 system/router.php``` +Then `composer test` will run the Unit Tests, which should be always executed successfully on any site. +Windows users should use the `composer test-windows` command. +You can also run a single unit test file, e.g. `composer test tests/unit/Grav/Common/AssetsTest.php` - Fenêtre à laisser ouverte! +To run phpstan tests, you should run: - - - dans autre fenetre, installer version admin - ```cd ~/webroot/nomdusite``` - ```bin/gpm selfupgrade``` (mise à jours) - - ```bin/gpm install admin``` (installe l’admin) - - ```bin/plugin login newuser``` (créer un nouvel utilisateur) - - - -# Pour lancer le site - - ```cd ~/chemin/dudossier/dev-epau.archi.fr``` - - pour premier lancement - - ```php bin/grav install``` - - ensuite - ```php -S localhost:8000 system/router.php``` - Fenêtre à laisser ouverte! - - ```bin/gpm install admin``` (installe l’admin) - - récupérer les comptes +* `composer phpstan` for global tests +* `composer phpstan-framework` for more strict tests +* `composer phpstan-plugins` to test all installed plugins diff --git a/SECURITY.md b/SECURITY.md index 3a27561..e2d0cfd 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,9 +7,15 @@ We are focusing our security updates on the following versions | Version | Supported | | ------- | ------------------ | | 1.7.x | :white_check_mark: | -| 1.6.x | :white_check_mark: | +| 1.6.x | :warning: | | < 1.6 | :x: | +## :warning: Versions + +Versions with :warning: will be supported for security issues, however you won't be able to update to them, you will need to manually update through the [`direct-install` command](https://learn.getgrav.org/17/admin-panel/tools). + +If you cannot update to the latest stable version available because, for example, your server does not meet the minimum PHP requirements, you can manually install a previous version by downloading the package from our Releases directory (https://github.com/getgrav/grav/releases). + ## Reporting a Vulnerability Please contact contact@getgrav.org with a detailed explaination of the security issue found and we will work with you to get it resolved as fast as possible. diff --git a/composer.json b/composer.json index 2d0a9cb..34d1e7e 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,8 @@ "psr/simple-cache": "^1.0", "psr/http-message": "^1.0", "psr/http-server-middleware": "^1.0", - "kodus/psr7-server": "*", + "psr/container": "~1.0.0", + "nyholm/psr7-server": "^1.0", "nyholm/psr7": "^1.3", "twig/twig": "~1.44", "erusev/parsedown": "^1.7", @@ -46,7 +47,7 @@ "gregwar/image": "dev-php8", "gregwar/cache": "dev-php8", "donatj/phpuseragentparser": "~1.1", - "pimple/pimple": "~3.3", + "pimple/pimple": "~3.3.0", "rockettheme/toolbox": "~1.5", "maximebf/debugbar": "~1.16", "league/climate": "^3.6", @@ -68,7 +69,8 @@ "phpunit/php-code-coverage": "~9.2", "victorjonsson/markdowndocs": "dev-master", "codeception/module-asserts": "^1.3", - "codeception/module-phpbrowser": "^1.0" + "codeception/module-phpbrowser": "^1.0", + "symfony/service-contracts": "*" }, "replace": { "symfony/polyfill-php72": "*", diff --git a/composer.lock b/composer.lock index 7f381b6..6ea862f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "32b6cbbe234714397aea3c6ed1eddf6b", + "content-hash": "4ae6fc7274c018b1bb34bb1b80bd62c5", "packages": [ { "name": "antoligy/dom-string-iterators", @@ -381,16 +381,16 @@ }, { "name": "donatj/phpuseragentparser", - "version": "v1.2.0", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/donatj/PhpUserAgent.git", - "reference": "978e66786bc392a09b24b152a8a695dadd230e60" + "reference": "f9a521726b2ce4c5173281ceaab5a02c05b691ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/donatj/PhpUserAgent/zipball/978e66786bc392a09b24b152a8a695dadd230e60", - "reference": "978e66786bc392a09b24b152a8a695dadd230e60", + "url": "https://api.github.com/repos/donatj/PhpUserAgent/zipball/f9a521726b2ce4c5173281ceaab5a02c05b691ef", + "reference": "f9a521726b2ce4c5173281ceaab5a02c05b691ef", "shasum": "" }, "require": { @@ -433,11 +433,11 @@ ], "support": { "issues": "https://github.com/donatj/PhpUserAgent/issues", - "source": "https://github.com/donatj/PhpUserAgent/tree/v1.2.0" + "source": "https://github.com/donatj/PhpUserAgent/tree/v1.3.0" }, "funding": [ { - "url": "https://www.paypal.me/donatj/15", + "url": "https://www.paypal.me/donatj/5", "type": "custom" }, { @@ -445,7 +445,7 @@ "type": "github" } ], - "time": "2020-12-29T05:36:08+00:00" + "time": "2021-02-18T04:30:49+00:00" }, { "name": "dragonmantank/cron-expression", @@ -763,18 +763,18 @@ "source": { "type": "git", "url": "https://github.com/getgrav/Image.git", - "reference": "70afaa75ea19856813124142c51f5fb2e9f1a285" + "reference": "ea23859700f32447a85e79d96f331e3d6c8897a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getgrav/Image/zipball/70afaa75ea19856813124142c51f5fb2e9f1a285", - "reference": "70afaa75ea19856813124142c51f5fb2e9f1a285", + "url": "https://api.github.com/repos/getgrav/Image/zipball/ea23859700f32447a85e79d96f331e3d6c8897a8", + "reference": "ea23859700f32447a85e79d96f331e3d6c8897a8", "shasum": "" }, "require": { "ext-gd": "*", "gregwar/cache": "dev-php8", - "php": "^5.3 || ^7.0 || ^8.0" + "php": "^5.6 || ^7.0 || ^8.0" }, "require-dev": { "sllh/php-cs-fixer-styleci-bridge": "~1.0", @@ -808,7 +808,7 @@ "support": { "source": "https://github.com/getgrav/Image/tree/php8" }, - "time": "2020-12-02T14:04:28+00:00" + "time": "2021-03-15T17:03:52+00:00" }, { "name": "guzzlehttp/psr7", @@ -887,16 +887,16 @@ }, { "name": "itsgoingd/clockwork", - "version": "v5.0.6", + "version": "v5.0.7", "source": { "type": "git", "url": "https://github.com/itsgoingd/clockwork.git", - "reference": "1de3f9f9fc22217aa024f79ecbdf0fde418fc0a1" + "reference": "e41ee368ff4dcc30d3f4563fe8bd80ed72b293b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/1de3f9f9fc22217aa024f79ecbdf0fde418fc0a1", - "reference": "1de3f9f9fc22217aa024f79ecbdf0fde418fc0a1", + "url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/e41ee368ff4dcc30d3f4563fe8bd80ed72b293b4", + "reference": "e41ee368ff4dcc30d3f4563fe8bd80ed72b293b4", "shasum": "" }, "require": { @@ -944,7 +944,7 @@ ], "support": { "issues": "https://github.com/itsgoingd/clockwork/issues", - "source": "https://github.com/itsgoingd/clockwork/tree/v5.0.6" + "source": "https://github.com/itsgoingd/clockwork/tree/v5.0.7" }, "funding": [ { @@ -952,65 +952,7 @@ "type": "github" } ], - "time": "2020-12-27T00:18:25+00:00" - }, - { - "name": "kodus/psr7-server", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/kodus/psr7-server.git", - "reference": "dcfd0116451b0f0e7c6b23b831757ed288347278" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/kodus/psr7-server/zipball/dcfd0116451b0f0e7c6b23b831757ed288347278", - "reference": "dcfd0116451b0f0e7c6b23b831757ed288347278", - "shasum": "" - }, - "require": { - "php": "^7.1", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.0" - }, - "replace": { - "nyholm/psr7-server": "^0.3" - }, - "require-dev": { - "nyholm/nsa": "^1.1", - "nyholm/psr7": "^1.0", - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Nyholm\\Psr7Server\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com" - }, - { - "name": "Martijn van der Ven", - "email": "martijn@vanderven.se" - } - ], - "description": "Helper classes to handle PSR-7 server requests", - "homepage": "http://tnyholm.se", - "keywords": [ - "psr-17", - "psr-7" - ], - "support": { - "source": "https://github.com/kodus/psr7-server/tree/master" - }, - "time": "2019-06-17T10:48:13+00:00" + "time": "2021-03-14T16:29:40+00:00" }, { "name": "league/climate", @@ -1421,16 +1363,16 @@ }, { "name": "nyholm/psr7", - "version": "1.3.2", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/Nyholm/psr7.git", - "reference": "a272953743c454ac4af9626634daaf5ab3ce1173" + "reference": "23ae1f00fbc6a886cbe3062ca682391b9cc7c37b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Nyholm/psr7/zipball/a272953743c454ac4af9626634daaf5ab3ce1173", - "reference": "a272953743c454ac4af9626634daaf5ab3ce1173", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/23ae1f00fbc6a886cbe3062ca682391b9cc7c37b", + "reference": "23ae1f00fbc6a886cbe3062ca682391b9cc7c37b", "shasum": "" }, "require": { @@ -1452,7 +1394,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.4-dev" } }, "autoload": { @@ -1482,7 +1424,7 @@ ], "support": { "issues": "https://github.com/Nyholm/psr7/issues", - "source": "https://github.com/Nyholm/psr7/tree/1.3.2" + "source": "https://github.com/Nyholm/psr7/tree/1.4.0" }, "funding": [ { @@ -1494,7 +1436,73 @@ "type": "github" } ], - "time": "2020-11-14T17:35:34+00:00" + "time": "2021-02-18T15:41:32+00:00" + }, + { + "name": "nyholm/psr7-server", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/Nyholm/psr7-server.git", + "reference": "5c134aeb5dd6521c7978798663470dabf0528c96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nyholm/psr7-server/zipball/5c134aeb5dd6521c7978798663470dabf0528c96", + "reference": "5c134aeb5dd6521c7978798663470dabf0528c96", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "require-dev": { + "nyholm/nsa": "^1.1", + "nyholm/psr7": "^1.3", + "phpunit/phpunit": "^7.0 || ^8.5 || ^9.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Nyholm\\Psr7Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "description": "Helper classes to handle PSR-7 server requests", + "homepage": "http://tnyholm.se", + "keywords": [ + "psr-17", + "psr-7" + ], + "support": { + "issues": "https://github.com/Nyholm/psr7-server/issues", + "source": "https://github.com/Nyholm/psr7-server/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/Zegnat", + "type": "github" + }, + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2020-11-15T15:26:20+00:00" }, { "name": "phive/twig-extensions-deferred", @@ -2238,16 +2246,16 @@ }, { "name": "symfony/console", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "24026c44fc37099fa145707fecd43672831b837a" + "reference": "c98349bda966c70d6c08b4cd8658377c94166492" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/24026c44fc37099fa145707fecd43672831b837a", - "reference": "24026c44fc37099fa145707fecd43672831b837a", + "url": "https://api.github.com/repos/symfony/console/zipball/c98349bda966c70d6c08b4cd8658377c94166492", + "reference": "c98349bda966c70d6c08b4cd8658377c94166492", "shasum": "" }, "require": { @@ -2307,7 +2315,7 @@ "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/console/tree/v4.4.19" + "source": "https://github.com/symfony/console/tree/v4.4.20" }, "funding": [ { @@ -2323,7 +2331,7 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-02-22T18:44:15+00:00" }, { "name": "symfony/contracts", @@ -2421,7 +2429,7 @@ }, { "name": "symfony/event-dispatcher", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -2484,7 +2492,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.19" + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.20" }, "funding": [ { @@ -2504,16 +2512,16 @@ }, { "name": "symfony/http-client", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "d8df50fe9229576b254c6822eb5cfff36c02c967" + "reference": "67c5af7489b3c2eea771abd973243f5c58f5fb40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/d8df50fe9229576b254c6822eb5cfff36c02c967", - "reference": "d8df50fe9229576b254c6822eb5cfff36c02c967", + "url": "https://api.github.com/repos/symfony/http-client/zipball/67c5af7489b3c2eea771abd973243f5c58f5fb40", + "reference": "67c5af7489b3c2eea771abd973243f5c58f5fb40", "shasum": "" }, "require": { @@ -2527,7 +2535,7 @@ "php-http/async-client-implementation": "*", "php-http/client-implementation": "*", "psr/http-client-implementation": "1.0", - "symfony/http-client-implementation": "1.1" + "symfony/http-client-implementation": "1.1|2.0" }, "require-dev": { "guzzlehttp/promises": "^1.4", @@ -2564,7 +2572,7 @@ "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-client/tree/v4.4.19" + "source": "https://github.com/symfony/http-client/tree/v4.4.20" }, "funding": [ { @@ -2580,7 +2588,7 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-02-25T18:06:45+00:00" }, { "name": "symfony/polyfill-ctype", @@ -2986,7 +2994,7 @@ }, { "name": "symfony/process", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/process.git", @@ -3027,7 +3035,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v4.4.19" + "source": "https://github.com/symfony/process/tree/v4.4.20" }, "funding": [ { @@ -3047,7 +3055,7 @@ }, { "name": "symfony/var-dumper", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", @@ -3116,7 +3124,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v4.4.19" + "source": "https://github.com/symfony/var-dumper/tree/v4.4.20" }, "funding": [ { @@ -3136,16 +3144,16 @@ }, { "name": "symfony/yaml", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "17ed9f14c1aa05b1a5cf2e2c5ef2d0be28058ef9" + "reference": "29e61305e1c79d25f71060903982ead8f533e267" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/17ed9f14c1aa05b1a5cf2e2c5ef2d0be28058ef9", - "reference": "17ed9f14c1aa05b1a5cf2e2c5ef2d0be28058ef9", + "url": "https://api.github.com/repos/symfony/yaml/zipball/29e61305e1c79d25f71060903982ead8f533e267", + "reference": "29e61305e1c79d25f71060903982ead8f533e267", "shasum": "" }, "require": { @@ -3187,7 +3195,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v4.4.19" + "source": "https://github.com/symfony/yaml/tree/v4.4.20" }, "funding": [ { @@ -3203,7 +3211,7 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-02-22T15:36:50+00:00" }, { "name": "twig/twig", @@ -3407,16 +3415,16 @@ }, { "name": "codeception/codeception", - "version": "4.1.17", + "version": "4.1.18", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "c153b1ab289b3e3109e685379aa8847c54ac2b68" + "reference": "f47547bac347dfb5ea5351ff91148cbcc08e6818" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/c153b1ab289b3e3109e685379aa8847c54ac2b68", - "reference": "c153b1ab289b3e3109e685379aa8847c54ac2b68", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/f47547bac347dfb5ea5351ff91148cbcc08e6818", + "reference": "f47547bac347dfb5ea5351ff91148cbcc08e6818", "shasum": "" }, "require": { @@ -3490,7 +3498,7 @@ ], "support": { "issues": "https://github.com/Codeception/Codeception/issues", - "source": "https://github.com/Codeception/Codeception/tree/4.1.17" + "source": "https://github.com/Codeception/Codeception/tree/4.1.18" }, "funding": [ { @@ -3498,7 +3506,7 @@ "type": "open_collective" } ], - "time": "2021-02-01T07:30:47+00:00" + "time": "2021-02-23T17:11:42+00:00" }, { "name": "codeception/lib-asserts", @@ -3556,16 +3564,16 @@ }, { "name": "codeception/lib-innerbrowser", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/Codeception/lib-innerbrowser.git", - "reference": "b7406c710684c255d9b067d7795269a5585a0406" + "reference": "693e116f81ef98eae98c43ef785a726faf87394e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/lib-innerbrowser/zipball/b7406c710684c255d9b067d7795269a5585a0406", - "reference": "b7406c710684c255d9b067d7795269a5585a0406", + "url": "https://api.github.com/repos/Codeception/lib-innerbrowser/zipball/693e116f81ef98eae98c43ef785a726faf87394e", + "reference": "693e116f81ef98eae98c43ef785a726faf87394e", "shasum": "" }, "require": { @@ -3610,9 +3618,9 @@ ], "support": { "issues": "https://github.com/Codeception/lib-innerbrowser/issues", - "source": "https://github.com/Codeception/lib-innerbrowser/tree/1.4.0" + "source": "https://github.com/Codeception/lib-innerbrowser/tree/1.4.1" }, - "time": "2021-01-29T18:17:25+00:00" + "time": "2021-03-02T08:01:54+00:00" }, { "name": "codeception/module-asserts", @@ -3987,16 +3995,16 @@ }, { "name": "guzzlehttp/promises", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "60d379c243457e073cff02bc323a2a86cb355631" + "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631", - "reference": "60d379c243457e073cff02bc323a2a86cb355631", + "url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d", + "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d", "shasum": "" }, "require": { @@ -4036,9 +4044,9 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.4.0" + "source": "https://github.com/guzzle/promises/tree/1.4.1" }, - "time": "2020-09-30T07:37:28+00:00" + "time": "2021-03-07T09:25:29+00:00" }, { "name": "myclabs/deep-copy", @@ -4216,16 +4224,16 @@ }, { "name": "phar-io/version", - "version": "3.0.4", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "e4782611070e50613683d2b9a57730e9a3ba5451" + "reference": "bae7c545bef187884426f042434e561ab1ddb182" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/e4782611070e50613683d2b9a57730e9a3ba5451", - "reference": "e4782611070e50613683d2b9a57730e9a3ba5451", + "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", + "reference": "bae7c545bef187884426f042434e561ab1ddb182", "shasum": "" }, "require": { @@ -4261,9 +4269,9 @@ "description": "Library for handling version information and constraints", "support": { "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.0.4" + "source": "https://github.com/phar-io/version/tree/3.1.0" }, - "time": "2020-12-13T23:18:30+00:00" + "time": "2021-02-23T14:00:09+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -4492,16 +4500,16 @@ }, { "name": "phpstan/phpstan", - "version": "0.12.77", + "version": "0.12.81", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "1f10b8c8d118d01e7b492f9707999d456be5812c" + "reference": "0dd5b0ebeff568f7000022ea5f04aa86ad3124b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/1f10b8c8d118d01e7b492f9707999d456be5812c", - "reference": "1f10b8c8d118d01e7b492f9707999d456be5812c", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0dd5b0ebeff568f7000022ea5f04aa86ad3124b8", + "reference": "0dd5b0ebeff568f7000022ea5f04aa86ad3124b8", "shasum": "" }, "require": { @@ -4532,7 +4540,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/0.12.77" + "source": "https://github.com/phpstan/phpstan/tree/0.12.81" }, "funding": [ { @@ -4548,7 +4556,7 @@ "type": "tidelift" } ], - "time": "2021-02-17T16:22:19+00:00" + "time": "2021-03-08T22:03:02+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -6040,16 +6048,16 @@ }, { "name": "symfony/browser-kit", - "version": "v5.2.3", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "b03b2057ed53ee4eab2e8f372084d7722b7b8ffd" + "reference": "3ca3a57ce9860318b20a924fec5daf5c6db44d93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/b03b2057ed53ee4eab2e8f372084d7722b7b8ffd", - "reference": "b03b2057ed53ee4eab2e8f372084d7722b7b8ffd", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/3ca3a57ce9860318b20a924fec5daf5c6db44d93", + "reference": "3ca3a57ce9860318b20a924fec5daf5c6db44d93", "shasum": "" }, "require": { @@ -6091,7 +6099,7 @@ "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/browser-kit/tree/v5.2.3" + "source": "https://github.com/symfony/browser-kit/tree/v5.2.4" }, "funding": [ { @@ -6107,11 +6115,11 @@ "type": "tidelift" } ], - "time": "2021-01-27T12:56:27+00:00" + "time": "2021-02-22T06:48:33+00:00" }, { "name": "symfony/css-selector", - "version": "v5.2.3", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", @@ -6156,7 +6164,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.2.3" + "source": "https://github.com/symfony/css-selector/tree/v5.2.4" }, "funding": [ { @@ -6176,16 +6184,16 @@ }, { "name": "symfony/dom-crawler", - "version": "v5.2.3", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "5d89ceb53ec65e1973a555072fac8ed5ecad3384" + "reference": "400e265163f65aceee7e904ef532e15228de674b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/5d89ceb53ec65e1973a555072fac8ed5ecad3384", - "reference": "5d89ceb53ec65e1973a555072fac8ed5ecad3384", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/400e265163f65aceee7e904ef532e15228de674b", + "reference": "400e265163f65aceee7e904ef532e15228de674b", "shasum": "" }, "require": { @@ -6230,7 +6238,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v5.2.3" + "source": "https://github.com/symfony/dom-crawler/tree/v5.2.4" }, "funding": [ { @@ -6246,20 +6254,20 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:01:46+00:00" + "time": "2021-02-15T18:55:04+00:00" }, { "name": "symfony/finder", - "version": "v5.2.3", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "4adc8d172d602008c204c2e16956f99257248e03" + "reference": "0d639a0943822626290d169965804f79400e6a04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/4adc8d172d602008c204c2e16956f99257248e03", - "reference": "4adc8d172d602008c204c2e16956f99257248e03", + "url": "https://api.github.com/repos/symfony/finder/zipball/0d639a0943822626290d169965804f79400e6a04", + "reference": "0d639a0943822626290d169965804f79400e6a04", "shasum": "" }, "require": { @@ -6291,7 +6299,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.2.3" + "source": "https://github.com/symfony/finder/tree/v5.2.4" }, "funding": [ { @@ -6307,7 +6315,7 @@ "type": "tidelift" } ], - "time": "2021-01-28T22:06:19+00:00" + "time": "2021-02-15T18:55:04+00:00" }, { "name": "theseer/tokenizer", @@ -6408,30 +6416,35 @@ }, { "name": "webmozart/assert", - "version": "1.9.1", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0 || ^8.0", + "php": "^7.2 || ^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<3.9.1" + "vimeo/psalm": "<4.6.1 || 4.6.2" }, "require-dev": { - "phpunit/phpunit": "^4.8.36 || ^7.5.13" + "phpunit/phpunit": "^8.5.13" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -6455,9 +6468,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.9.1" + "source": "https://github.com/webmozarts/assert/tree/1.10.0" }, - "time": "2020-07-08T17:02:28+00:00" + "time": "2021-03-09T10:59:23+00:00" } ], "aliases": [], diff --git a/system/blueprints/config/system.yaml b/system/blueprints/config/system.yaml index 538fd08..d2be69c 100644 --- a/system/blueprints/config/system.yaml +++ b/system/blueprints/config/system.yaml @@ -177,39 +177,47 @@ form: label: PLUGIN_ADMIN.APPEND_URL_EXT help: PLUGIN_ADMIN.APPEND_URL_EXT_HELP - pages.redirect_default_route: - type: toggle - label: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE - help: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE_HELP - highlight: 0 - options: - 1: PLUGIN_ADMIN.YES - 0: PLUGIN_ADMIN.NO - validate: - type: bool - pages.redirect_default_code: type: select size: medium classes: fancy label: PLUGIN_ADMIN.REDIRECT_DEFAULT_CODE help: PLUGIN_ADMIN.REDIRECT_DEFAULT_CODE_HELP + default: 302 options: - 301: 301 - Permanent - 302: 302 - Found - 303: 303 - Other - 304: 304 - Not Modified + 301: PLUGIN_ADMIN.REDIRECT_OPTION_301 + 302: PLUGIN_ADMIN.REDIRECT_OPTION_302 + 303: PLUGIN_ADMIN.REDIRECT_OPTION_303 + + pages.redirect_default_route: + type: select + size: medium + classes: fancy + label: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE + help: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE_HELP + default: 0 + options: + 0: PLUGIN_ADMIN.REDIRECT_OPTION_NO_REDIRECT + 1: PLUGIN_ADMIN.REDIRECT_OPTION_DEFAULT_REDIRECT + 301: PLUGIN_ADMIN.REDIRECT_OPTION_301 + 302: PLUGIN_ADMIN.REDIRECT_OPTION_302 + validate: + type: int pages.redirect_trailing_slash: - type: toggle + type: select + size: medium + classes: fancy label: PLUGIN_ADMIN.REDIRECT_TRAILING_SLASH help: PLUGIN_ADMIN.REDIRECT_TRAILING_SLASH_HELP - highlight: 1 + default: 1 options: - 1: PLUGIN_ADMIN.YES - 0: PLUGIN_ADMIN.NO + 0: PLUGIN_ADMIN.REDIRECT_OPTION_NO_REDIRECT + 1: PLUGIN_ADMIN.REDIRECT_OPTION_DEFAULT_REDIRECT + 301: PLUGIN_ADMIN.REDIRECT_OPTION_301 + 302: PLUGIN_ADMIN.REDIRECT_OPTION_302 validate: - type: bool + type: int pages.ignore_hidden: type: toggle @@ -1006,6 +1014,17 @@ form: validate: type: bool + assets.enable_asset_sri: + type: toggle + label: PLUGIN_ADMIN.ENABLED_SRI_ON_ASSETS + help: PLUGIN_ADMIN.ENABLED_SRI_ON_ASSETS_HELP + highlight: 0 + options: + 1: PLUGIN_ADMIN.YES + 0: PLUGIN_ADMIN.NO + validate: + type: bool + assets.collections: type: multilevel label: PLUGIN_ADMIN.COLLECTIONS diff --git a/system/blueprints/flex/pages.yaml b/system/blueprints/flex/pages.yaml index 963ce6d..ee2e7e5 100644 --- a/system/blueprints/flex/pages.yaml +++ b/system/blueprints/flex/pages.yaml @@ -176,7 +176,7 @@ config: indexed: true # Set default ordering of the pages ordering: - key: ASC + storage_key: ASC search: # Search options options: diff --git a/system/config/system.yaml b/system/config/system.yaml index 5c29a78..ffb98f2 100644 --- a/system/config/system.yaml +++ b/system/config/system.yaml @@ -75,9 +75,9 @@ pages: last_modified: false # Set the last modified date header based on file modification timestamp etag: true # Set the etag header tag vary_accept_encoding: false # Add `Vary: Accept-Encoding` header - redirect_default_route: false # Automatically redirect to a page's default route - redirect_default_code: 302 # Default code to use for redirects - redirect_trailing_slash: true # Handle automatically or 302 redirect a trailing / URL + redirect_default_code: 302 # Default code to use for redirects: 301|302|303 + redirect_trailing_slash: 1 # Always redirect trailing slash with redirect code 0|1|301|302 (0: no redirect, 1: use default code) + redirect_default_route: 0 # Always redirect to page's default route using code 0|1|301|302, also removes .htm and .html extensions ignore_files: [.DS_Store] # Files to ignore in Pages ignore_folders: [.git, .idea] # Folders to ignore in Pages ignore_hidden: true # Ignore all Hidden files and folders @@ -127,6 +127,7 @@ assets: # Configuration for Assets Mana js_pipeline_before_excludes: true # Render the pipeline before any excluded files js_minify: true # Minify the JS during pipelining enable_asset_timestamp: false # Enable asset timestamps + enable_asset_sri: false # Enable asset SRI collections: jquery: system://assets/jquery/jquery-2.x.min.js diff --git a/system/defines.php b/system/defines.php index d0fd873..6c4b812 100644 --- a/system/defines.php +++ b/system/defines.php @@ -8,7 +8,7 @@ // Some standard defines define('GRAV', true); -define('GRAV_VERSION', '1.7.7'); +define('GRAV_VERSION', '1.7.8'); define('GRAV_SCHEMA', '1.7.0_2020-11-20_1'); define('GRAV_TESTING', false); diff --git a/system/src/Grav/Common/Assets/BaseAsset.php b/system/src/Grav/Common/Assets/BaseAsset.php index 579b1f9..423c842 100644 --- a/system/src/Grav/Common/Assets/BaseAsset.php +++ b/system/src/Grav/Common/Assets/BaseAsset.php @@ -10,6 +10,7 @@ namespace Grav\Common\Assets; use Grav\Common\Assets\Traits\AssetUtilsTrait; +use Grav\Common\Config\Config; use Grav\Common\Grav; use Grav\Common\Uri; use Grav\Common\Utils; @@ -171,6 +172,31 @@ abstract class BaseAsset extends PropertyObject return $this; } + + /** + * Receive asset location and return the SRI integrity hash + * + * @param $input + * + * @return string + */ + public static function integrityHash( $input ) + { + $grav = Grav::instance(); + + $assetsConfig = $grav['config']->get('system.assets'); + + if ( !empty($assetsConfig['enable_asset_sri']) && $assetsConfig['enable_asset_sri'] ) + { + $dataToHash = file_get_contents( GRAV_ROOT . $input); + + $hash = hash('sha256', $dataToHash, true); + $hash_base64 = base64_encode($hash); + return ' integrity="sha256-' . $hash_base64 . '"'; + } + + return ''; + } /** diff --git a/system/src/Grav/Common/Assets/Css.php b/system/src/Grav/Common/Assets/Css.php index b1f0a48..4c6a9c9 100644 --- a/system/src/Grav/Common/Assets/Css.php +++ b/system/src/Grav/Common/Assets/Css.php @@ -47,6 +47,6 @@ class Css extends BaseAsset return "\n"; } - return 'renderAttributes() . ">\n"; + return 'renderAttributes() . $this->integrityHash($this->asset) . ">\n"; } } diff --git a/system/src/Grav/Common/Assets/Js.php b/system/src/Grav/Common/Assets/Js.php index 9946bd8..fc2a472 100644 --- a/system/src/Grav/Common/Assets/Js.php +++ b/system/src/Grav/Common/Assets/Js.php @@ -43,6 +43,6 @@ class Js extends BaseAsset return 'renderAttributes() . ">\n" . trim($buffer) . "\n\n"; } - return '\n"; + return '\n"; } } diff --git a/system/src/Grav/Common/Assets/Pipeline.php b/system/src/Grav/Common/Assets/Pipeline.php index 9b44fd8..7aef0e1 100644 --- a/system/src/Grav/Common/Assets/Pipeline.php +++ b/system/src/Grav/Common/Assets/Pipeline.php @@ -9,6 +9,7 @@ namespace Grav\Common\Assets; +use Grav\Common\Assets\BaseAsset; use Grav\Common\Assets\Traits\AssetUtilsTrait; use Grav\Common\Config\Config; use Grav\Common\Grav; @@ -148,7 +149,7 @@ class Pipeline extends PropertyObject $output = "\n"; } else { $this->asset = $relative_path; - $output = 'renderAttributes() . ">\n"; + $output = 'renderAttributes() . BaseAsset::integrityHash($this->asset) . ">\n"; } return $output; @@ -211,7 +212,7 @@ class Pipeline extends PropertyObject $output = 'renderAttributes(). ">\n" . $buffer . "\n\n"; } else { $this->asset = $relative_path; - $output = '\n"; + $output = '\n"; } return $output; diff --git a/system/src/Grav/Common/Cache.php b/system/src/Grav/Common/Cache.php index 24f1d40..6527091 100644 --- a/system/src/Grav/Common/Cache.php +++ b/system/src/Grav/Common/Cache.php @@ -71,6 +71,7 @@ class Cache extends Getters 'cache://twig/', 'cache://doctrine/', 'cache://compiled/', + 'cache://clockwork/', 'cache://validated-', 'cache://images', 'asset://', @@ -80,6 +81,7 @@ class Cache extends Getters 'cache://twig/', 'cache://doctrine/', 'cache://compiled/', + 'cache://clockwork/', 'cache://validated-', 'asset://', ]; @@ -311,7 +313,7 @@ class Cache extends Getters if ($password && !$redis->auth($password)) { throw new \RedisException('Redis authentication failed'); } - + // Select alternate ( !=0 ) database ID if set if ($databaseId && !$redis->select($databaseId)) { throw new \RedisException('Could not select alternate Redis database ID'); @@ -498,7 +500,7 @@ class Cache extends Getters $anything = true; } } elseif (is_dir($file)) { - if (Folder::delete($file)) { + if (Folder::delete($file, false)) { $anything = true; } } diff --git a/system/src/Grav/Common/Flex/Types/Pages/PageIndex.php b/system/src/Grav/Common/Flex/Types/Pages/PageIndex.php index fbf0df4..c5b7ce9 100644 --- a/system/src/Grav/Common/Flex/Types/Pages/PageIndex.php +++ b/system/src/Grav/Common/Flex/Types/Pages/PageIndex.php @@ -21,13 +21,16 @@ use Grav\Common\Grav; use Grav\Common\Page\Header; use Grav\Common\Page\Interfaces\PageCollectionInterface; use Grav\Common\Page\Interfaces\PageInterface; +use Grav\Common\User\Interfaces\UserInterface; use Grav\Common\Utils; use Grav\Framework\Flex\FlexDirectory; -use Grav\Framework\Flex\Interfaces\FlexCollectionInterface; use Grav\Framework\Flex\Interfaces\FlexStorageInterface; use Grav\Framework\Flex\Pages\FlexPageIndex; use InvalidArgumentException; use RuntimeException; +use function array_slice; +use function count; +use function in_array; use function is_array; use function is_string; @@ -299,7 +302,33 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface 'type' => ['root', 'dir'], ]; - return $this->getLevelListingRecurse($options); + $key = 'page.idx.lev.' . sha1(json_encode($options, JSON_THROW_ON_ERROR) . $this->getCacheKey()); + $checksum = $this->getCacheChecksum(); + + $cache = $this->getCache('object'); + + /** @var Debugger $debugger */ + $debugger = Grav::instance()['debugger']; + + $result = null; + try { + $cached = $cache->get($key); + $test = $cached[0] ?? null; + $result = $test === $checksum ? ($cached[1] ?? null) : null; + } catch (\Psr\SimpleCache\InvalidArgumentException $e) { + $debugger->addException($e); + } + + try { + if (null === $result) { + $result = $this->getLevelListingRecurse($options); + $cache->set($key, [$checksum, $result]); + } + } catch (\Psr\SimpleCache\InvalidArgumentException $e) { + $debugger->addException($e); + } + + return $result; } /** @@ -429,6 +458,9 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface $selectedChildren = $selectedChildren->order($sortby, $order, $custom ?? null); } + /** @var UserInterface|null $user */ + $user = Grav::instance()['user'] ?? null; + /** @var PageObject $child */ foreach ($selectedChildren as $child) { $selected = $child->path() === $extra; @@ -482,7 +514,7 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface 'visible' => $child->visible(), 'routable' => $child->routable(), 'tags' => $tags, - 'actions' => $this->getListingActions($child), + 'actions' => $this->getListingActions($child, $user), ]; $extras = array_filter($extras, static function ($v) { return $v !== null; @@ -535,20 +567,21 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface /** * @param PageObject $object + * @param UserInterface $user * @return array */ - protected function getListingActions(PageObject $object): array + protected function getListingActions(PageObject $object, UserInterface $user): array { $actions = []; - if ($object->isAuthorized('read')) { + if ($object->isAuthorized('read', null, $user)) { $actions[] = 'preview'; $actions[] = 'edit'; } - if ($object->isAuthorized('update')) { + if ($object->isAuthorized('update', null, $user)) { $actions[] = 'copy'; $actions[] = 'move'; } - if ($object->isAuthorized('delete')) { + if ($object->isAuthorized('delete', null, $user)) { $actions[] = 'delete'; } diff --git a/system/src/Grav/Common/Flex/Types/Pages/PageObject.php b/system/src/Grav/Common/Flex/Types/Pages/PageObject.php index 56c0527..2d45b91 100644 --- a/system/src/Grav/Common/Flex/Types/Pages/PageObject.php +++ b/system/src/Grav/Common/Flex/Types/Pages/PageObject.php @@ -62,7 +62,6 @@ class PageObject extends FlexPageObject /** @var string Language code, eg: 'en' */ protected $language; - /** @var string File format, eg. 'md' */ protected $format; @@ -78,6 +77,7 @@ class PageObject extends FlexPageObject 'path' => true, 'full_order' => true, 'filterBy' => true, + 'translated' => false, ] + parent::getCachedMethods(); } @@ -92,6 +92,11 @@ class PageObject extends FlexPageObject } } + public function translated(): bool + { + return $this->translatedLanguages(true) ? true : false; + } + /** * @param string|array $query * @return Route|null @@ -223,7 +228,7 @@ class PageObject extends FlexPageObject } // Reorder siblings. - $siblings = is_array($reorder) ? $this->reorderSiblings($reorder) : []; + $siblings = is_array($reorder) ? ($this->reorderSiblings($reorder) ?? []) : []; $data = $this->prepareStorage(); unset($data['header']); @@ -289,6 +294,9 @@ class PageObject extends FlexPageObject $grav->fireEvent('onAdminAfterSave', new Event(['type' => 'flex', 'directory' => $this->getFlexDirectory(), 'object' => $this])); } + // Reset original after save events have all been called. + $this->_original = null; + return $instance; } @@ -308,13 +316,14 @@ class PageObject extends FlexPageObject $this->_reorder = []; $this->setProperty('parent_key', $parent->getStorageKey()); + $this->storeOriginal(); return $this; } /** * @param array $ordering - * @return PageCollection + * @return PageCollection|null */ protected function reorderSiblings(array $ordering) { @@ -324,17 +333,35 @@ class PageObject extends FlexPageObject $newParentKey = $this->getProperty('parent_key'); $isMoved = $oldParentKey !== $newParentKey; $order = !$isMoved ? $this->order() : false; + if ($order !== false) { + $order = (int)$order; + } $parent = $this->parent(); if (!$parent) { throw new RuntimeException('Cannot reorder a page which has no parent'); } - /** @var PageCollection|null $siblings */ + /** @var PageCollection $siblings */ $siblings = $parent->children(); + $siblings = $siblings->getCollection()->withOrdered(); - /** @var PageCollection|null $siblings */ - $siblings = $siblings->getCollection()->withOrdered()->orderBy(['order' => 'ASC']); + // Handle special case where ordering isn't given. + if ($ordering === []) { + if ($order >= 999999) { + // Set ordering to point to be the last item. + $order = 0; + foreach ($siblings as $sibling) { + $order = max($order, (int)$sibling->order()); + } + $this->order($order + 1); + } + + // Do not change sibling ordering. + return null; + } + + $siblings = $siblings->orderBy(['order' => 'ASC']); if ($storageKey !== null) { if ($order !== false) { @@ -378,7 +405,9 @@ class PageObject extends FlexPageObject throw new RuntimeException("New parent page '{$parentKey}' not found."); } } - $newSiblings = $newParent->children()->getCollection()->withOrdered(); + /** @var PageCollection $newSiblings */ + $newSiblings = $newParent->children(); + $newSiblings = $newSiblings->getCollection()->withOrdered(); $order = 0; foreach ($newSiblings as $sibling) { $order = max($order, (int)$sibling->order()); @@ -584,14 +613,17 @@ class PageObject extends FlexPageObject unset($elements['ordering'], $elements['order']); } elseif (array_key_exists('ordering', $elements) && array_key_exists('order', $elements)) { // Store ordering. - $this->_reorder = !empty($elements['order']) ? explode(',', $elements['order']) : []; + $ordering = $elements['order'] ?? null; + $this->_reorder = !empty($ordering) ? explode(',', $ordering) : []; $order = false; if ((bool)($elements['ordering'] ?? false)) { - $order = 999999; + $order = $this->order(); + if ($order === false) { + $order = 999999; + } } - $this->order(); $elements['order'] = $order; } diff --git a/system/src/Grav/Common/Flex/Types/Pages/Storage/PageStorage.php b/system/src/Grav/Common/Flex/Types/Pages/Storage/PageStorage.php index a235174..0ccb856 100644 --- a/system/src/Grav/Common/Flex/Types/Pages/Storage/PageStorage.php +++ b/system/src/Grav/Common/Flex/Types/Pages/Storage/PageStorage.php @@ -110,6 +110,9 @@ class PageStorage extends FolderStorage } } catch (RuntimeException $e) { $frontmatter = 'ERROR: ' . $e->getMessage(); + } finally { + $file->free(); + unset($file); } return $frontmatter; @@ -127,6 +130,9 @@ class PageStorage extends FolderStorage $raw = $file->raw(); } catch (RuntimeException $e) { $raw = 'ERROR: ' . $e->getMessage(); + } finally { + $file->free(); + unset($file); } return $raw; @@ -407,7 +413,7 @@ class PageStorage extends FolderStorage if (!$isClone && $file->exists()) { /** @var UniformResourceLocator $locator */ $locator = $grav['locator']; - $toPath = $locator->isStream($newFilepath) ? $locator->findResource($newFilepath, true, true) : $newFilepath; + $toPath = $locator->isStream($newFilepath) ? $locator->findResource($newFilepath, true, true) : GRAV_ROOT . "/{$newFilepath}"; $success = $file->rename($toPath); if (!$success) { throw new RuntimeException("Changing page template failed: {$oldFilepath} => {$newFilepath}"); @@ -439,16 +445,19 @@ class PageStorage extends FolderStorage } else { $debugger->addMessage('Page content has not been changed, do not update the file', 'debug'); } - - /** @var UniformResourceLocator $locator */ - $locator = Grav::instance()['locator']; - if ($locator->isStream($newFolder)) { - $locator->clearCache(); - } } catch (RuntimeException $e) { $name = isset($file) ? $file->filename() : $newKey; throw new RuntimeException(sprintf('Flex saveRow(%s): %s', $name, $e->getMessage())); + } finally { + /** @var UniformResourceLocator $locator */ + $locator = Grav::instance()['locator']; + $locator->clearCache(); + + if (isset($file)) { + $file->free(); + unset($file); + } } $row['__META'] = $this->getObjectMeta($newKey, true); @@ -512,7 +521,11 @@ class PageStorage extends FolderStorage $locator = Grav::instance()['locator']; if (mb_strpos($key, '@@') === false) { $path = $this->getStoragePath($key); - $path = $path ? $locator->findResource($path) : null; + if (is_string($path)) { + $path = $locator->isStream($path) ? $locator->findResource($path) : GRAV_ROOT . "/{$path}"; + } else { + $path = null; + } } else { $path = null; } diff --git a/system/src/Grav/Common/Flex/Types/Pages/Traits/PageTranslateTrait.php b/system/src/Grav/Common/Flex/Types/Pages/Traits/PageTranslateTrait.php index e2de494..dff42c9 100644 --- a/system/src/Grav/Common/Flex/Types/Pages/Traits/PageTranslateTrait.php +++ b/system/src/Grav/Common/Flex/Types/Pages/Traits/PageTranslateTrait.php @@ -67,7 +67,7 @@ trait PageTranslateTrait if (!$folder) { return []; } - $folder = $locator($folder); + $folder = $locator->isStream($folder) ? $locator->getResource($folder) : GRAV_ROOT . "/{$folder}"; $list = array_fill_keys($languages, null); foreach ($translated as $languageCode => $languageFile) { diff --git a/system/src/Grav/Common/Grav.php b/system/src/Grav/Common/Grav.php index 048f7d4..d9ad289 100644 --- a/system/src/Grav/Common/Grav.php +++ b/system/src/Grav/Common/Grav.php @@ -426,12 +426,18 @@ class Grav extends Container // Clean route for redirect $route = preg_replace("#^\/[\\\/]+\/#", '/', $route); - // Check for code in route - $regex = '/.*(\[(30[1-7])\])$/'; - preg_match($regex, $route, $matches); - if ($matches) { - $route = str_replace($matches[1], '', $matches[0]); - $code = $matches[2]; + if (null !== $code || $code < 300 || $code > 399) { + $code = null; + } + + 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); + if ($matches) { + $route = str_replace($matches[1], '', $matches[0]); + $code = $matches[2]; + } } if ($code === null) { diff --git a/system/src/Grav/Common/Helpers/LogViewer.php b/system/src/Grav/Common/Helpers/LogViewer.php index 1e3e8d2..a03fde8 100644 --- a/system/src/Grav/Common/Helpers/LogViewer.php +++ b/system/src/Grav/Common/Helpers/LogViewer.php @@ -34,7 +34,7 @@ class LogViewer public function objectTail($filepath, $lines = 1, $desc = true) { $data = $this->tail($filepath, $lines); - $tailed_log = explode(PHP_EOL, $data); + $tailed_log = $data ? explode(PHP_EOL, $data) : []; $line_objects = []; foreach ($tailed_log as $line) { @@ -54,13 +54,13 @@ class LogViewer public function tail($filepath, $lines = 1) { - $f = @fopen($filepath, "rb"); + $f = $filepath ? @fopen($filepath, 'rb') : false; if ($f === false) { return false; - } else { - $buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096)); } + $buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096)); + fseek($f, -1, SEEK_END); if (fread($f, 1) != "\n") { $lines -= 1; diff --git a/system/src/Grav/Common/Page/Interfaces/PageRoutableInterface.php b/system/src/Grav/Common/Page/Interfaces/PageRoutableInterface.php index 8fc3c20..2900266 100644 --- a/system/src/Grav/Common/Page/Interfaces/PageRoutableInterface.php +++ b/system/src/Grav/Common/Page/Interfaces/PageRoutableInterface.php @@ -63,7 +63,7 @@ interface PageRoutableInterface * the parents route and the current Page's slug. * * @param string|null $var Set new default route. - * @return string The route for the Page. + * @return string|null The route for the Page. */ public function route($var = null); diff --git a/system/src/Grav/Common/Page/Markdown/Excerpts.php b/system/src/Grav/Common/Page/Markdown/Excerpts.php index 1a36602..3317217 100644 --- a/system/src/Grav/Common/Page/Markdown/Excerpts.php +++ b/system/src/Grav/Common/Page/Markdown/Excerpts.php @@ -278,10 +278,10 @@ class Excerpts ); } - $defaults = $config['images']['defaults'] ?? []; + $defaults = $this->config['images']['defaults'] ?? []; if (count($defaults)) { foreach ($defaults as $method => $params) { - if (!array_search($method, array_column($actions, 'method'))) { + if (array_search($method, array_column($actions, 'method')) === false) { $actions[] = [ 'method' => $method, 'params' => $params, diff --git a/system/src/Grav/Common/Page/Page.php b/system/src/Grav/Common/Page/Page.php index 9d037d2..baac905 100644 --- a/system/src/Grav/Common/Page/Page.php +++ b/system/src/Grav/Common/Page/Page.php @@ -1875,7 +1875,7 @@ class Page implements PageInterface * the parents route and the current Page's slug. * * @param string|null $var Set new default route. - * @return string The route for the Page. + * @return string|null The route for the Page. */ public function route($var = null) { diff --git a/system/src/Grav/Common/Page/Pages.php b/system/src/Grav/Common/Page/Pages.php index 0c430fd..4f64502 100644 --- a/system/src/Grav/Common/Page/Pages.php +++ b/system/src/Grav/Common/Page/Pages.php @@ -769,6 +769,9 @@ class Pages public function get($path) { $path = (string)$path; + if ($path === '') { + return null; + } // Check for local instances first. if (array_key_exists($path, $this->instances)) { @@ -777,14 +780,26 @@ class Pages $instance = $this->index[$path] ?? null; if (is_string($instance)) { - /** @var Language $language */ - $language = $this->grav['language']; - $lang = $language->getActive(); - if ($lang) { - $instance .= ':' . $lang; + if ($this->directory) { + /** @var Language $language */ + $language = $this->grav['language']; + $lang = $language->getActive(); + if ($lang) { + $languages = $language->getFallbackLanguages($lang, true); + $key = $instance; + $instance = null; + foreach ($languages as $code) { + $test = $code ? $key . ':' . $code : $key; + if (($instance = $this->directory->getObject($test, 'flex_key')) !== null) { + break; + } + } + } else { + $instance = $this->directory->getObject($instance, 'flex_key'); + } } - $instance = $this->directory ? $this->directory->getObject($instance, 'flex_key') : null; - if ($instance) { + + if ($instance instanceof PageInterface) { if ($this->fire_events && method_exists($instance, 'initialize')) { $instance->initialize(); } @@ -1159,7 +1174,14 @@ class Pages $event->types = $types; $grav->fireEvent('onGetPageBlueprints', $event); - $types->scanBlueprints('theme://blueprints/'); + $types->init(); + + // Try new location first. + $lookup = 'theme://blueprints/pages/'; + if (!is_dir($lookup)) { + $lookup = 'theme://blueprints/'; + } + $types->scanBlueprints($lookup); // Scan templates $event = new Event(); diff --git a/system/src/Grav/Common/Page/Types.php b/system/src/Grav/Common/Page/Types.php index 051610f..b9d8f95 100644 --- a/system/src/Grav/Common/Page/Types.php +++ b/system/src/Grav/Common/Page/Types.php @@ -32,22 +32,23 @@ class Types implements \ArrayAccess, \Iterator, \Countable /** @var array */ protected $items; /** @var array */ - protected $systemBlueprints; + protected $systemBlueprints = []; /** * @param string $type * @param Blueprint|null $blueprint + * @return void */ public function register($type, $blueprint = null) { if (!isset($this->items[$type])) { $this->items[$type] = []; - } elseif (!$blueprint) { + } elseif (null === $blueprint) { return; } - if (!$blueprint && $this->systemBlueprints) { - $blueprint = $this->systemBlueprints[$type] ?? $this->systemBlueprints['default']; + if (null === $blueprint) { + $blueprint = $this->systemBlueprints[$type] ?? $this->systemBlueprints['default'] ?? null; } if ($blueprint) { @@ -55,8 +56,23 @@ class Types implements \ArrayAccess, \Iterator, \Countable } } + /** + * @return void + */ + public function init() + { + if (null === $this->systemBlueprints) { + // Register all blueprints from the blueprints stream. + $this->systemBlueprints = $this->findBlueprints('blueprints://pages'); + foreach ($this->systemBlueprints as $type => $blueprint) { + $this->register($type); + } + } + } + /** * @param string $uri + * @return void */ public function scanBlueprints($uri) { @@ -64,15 +80,6 @@ class Types implements \ArrayAccess, \Iterator, \Countable throw new InvalidArgumentException('First parameter must be URI'); } - if (null === $this->systemBlueprints) { - $this->systemBlueprints = $this->findBlueprints('blueprints://pages'); - - // Register default by default. - $this->register('default'); - - $this->register('external'); - } - foreach ($this->findBlueprints($uri) as $type => $blueprint) { $this->register($type, $blueprint); } @@ -80,6 +87,7 @@ class Types implements \ArrayAccess, \Iterator, \Countable /** * @param string $uri + * @return void */ public function scanTemplates($uri) { diff --git a/system/src/Grav/Common/Plugin.php b/system/src/Grav/Common/Plugin.php index d075860..65b11db 100644 --- a/system/src/Grav/Common/Plugin.php +++ b/system/src/Grav/Common/Plugin.php @@ -16,6 +16,7 @@ use Grav\Common\Page\Interfaces\PageInterface; use Grav\Common\Config\Config; use LogicException; use RocketTheme\Toolbox\File\YamlFile; +use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use function defined; @@ -35,11 +36,11 @@ class Plugin implements EventSubscriberInterface, ArrayAccess /** @var Grav */ protected $grav; - /** @var Config */ + /** @var Config|null */ protected $config; /** @var bool */ protected $active = true; - /** @var Blueprint */ + /** @var Blueprint|null */ protected $blueprint; /** @@ -127,21 +128,25 @@ class Plugin implements EventSubscriberInterface, ArrayAccess */ protected function isPluginActiveAdmin($plugin_route) { - $should_run = false; + $active = false; + /** @var Uri $uri */ $uri = $this->grav['uri']; + /** @var Config $config */ + $config = $this->config ?? $this->grav['config']; - if (strpos($uri->path(), $this->config->get('plugins.admin.route') . '/' . $plugin_route) === false) { - $should_run = false; + if (strpos($uri->path(), $config->get('plugins.admin.route') . '/' . $plugin_route) === false) { + $active = false; } elseif (isset($uri->paths()[1]) && $uri->paths()[1] === $plugin_route) { - $should_run = true; + $active = true; } - return $should_run; + return $active; } /** * @param array $events + * @return void */ protected function enable(array $events) { @@ -164,22 +169,18 @@ class Plugin implements EventSubscriberInterface, ArrayAccess /** * @param array $params * @param string $eventName + * @return int */ private function getPriority($params, $eventName) { - $grav = Grav::instance(); $override = implode('.', ['priorities', $this->name, $eventName, $params[0]]); - if ($grav['config']->get($override) !== null) { - return $grav['config']->get($override); - } - if (isset($params[1])) { - return $params[1]; - } - return 0; + + return $this->grav['config']->get($override) ?? $params[1] ?? 0; } /** * @param array $events + * @return void */ protected function disable(array $events) { @@ -207,12 +208,13 @@ class Plugin implements EventSubscriberInterface, ArrayAccess */ public function offsetExists($offset) { - $this->loadBlueprint(); - if ($offset === 'title') { $offset = 'name'; } - return isset($this->blueprint[$offset]); + + $blueprint = $this->getBlueprint(); + + return isset($blueprint[$offset]); } /** @@ -223,12 +225,13 @@ class Plugin implements EventSubscriberInterface, ArrayAccess */ public function offsetGet($offset) { - $this->loadBlueprint(); - if ($offset === 'title') { $offset = 'name'; } - return $this->blueprint[$offset] ?? null; + + $blueprint = $this->getBlueprint(); + + return $blueprint[$offset] ?? null; } /** @@ -281,9 +284,12 @@ class Plugin implements EventSubscriberInterface, ArrayAccess */ protected function parseLinks($content, $function, $internal_regex = '(.*)') { - $regex = '/\[plugin:(?:' . $this->name . ')\]\(' . $internal_regex . '\)/i'; + $regex = '/\[plugin:(?:' . preg_quote($this->name, '/') . ')\]\(' . $internal_regex . '\)/i'; - return preg_replace_callback($regex, $function, $content); + $result = preg_replace_callback($regex, $function, $content); + \assert($result !== null); + + return $result; } /** @@ -301,9 +307,12 @@ class Plugin implements EventSubscriberInterface, ArrayAccess */ protected function mergeConfig(PageInterface $page, $deep = false, $params = [], $type = 'plugins') { + /** @var Config $config */ + $config = $this->config ?? $this->grav['config']; + $class_name = $this->name; $class_name_merged = $class_name . '.merged'; - $defaults = $this->config->get($type . '.' . $class_name, []); + $defaults = $config->get($type . '.' . $class_name, []); $page_header = $page->header(); $header = []; @@ -356,23 +365,26 @@ class Plugin implements EventSubscriberInterface, ArrayAccess /** * Persists to disk the plugin parameters currently stored in the Grav Config object * - * @param string $plugin_name The name of the plugin whose config it should store. - * + * @param string $name The name of the plugin whose config it should store. * @return bool */ - public static function saveConfig($plugin_name) + public static function saveConfig($name) { - if (!$plugin_name) { + if (!$name) { return false; } $grav = Grav::instance(); + + /** @var UniformResourceLocator $locator */ $locator = $grav['locator']; - $filename = 'config://plugins/' . $plugin_name . '.yaml'; - $file = YamlFile::instance($locator->findResource($filename, true, true)); - $content = $grav['config']->get('plugins.' . $plugin_name); + + $filename = 'config://plugins/' . $name . '.yaml'; + $file = YamlFile::instance((string)$locator->findResource($filename, true, true)); + $content = $grav['config']->get('plugins.' . $name); $file->save($content); $file->free(); + unset($file); return true; } @@ -384,21 +396,28 @@ class Plugin implements EventSubscriberInterface, ArrayAccess */ public function getBlueprint() { - if (!$this->blueprint) { + if (null === $this->blueprint) { $this->loadBlueprint(); + \assert($this->blueprint instanceof Blueprint); } + return $this->blueprint; } /** * Load blueprints. + * + * @return void */ protected function loadBlueprint() { - if (!$this->blueprint) { + if (null === $this->blueprint) { $grav = Grav::instance(); + /** @var Plugins $plugins */ $plugins = $grav['plugins']; - $this->blueprint = $plugins->get($this->name)->blueprints(); + $data = $plugins->get($this->name); + \assert($data !== null); + $this->blueprint = $data->blueprints(); } } } diff --git a/system/src/Grav/Common/Plugins.php b/system/src/Grav/Common/Plugins.php index f1d7b8e..be8f43b 100644 --- a/system/src/Grav/Common/Plugins.php +++ b/system/src/Grav/Common/Plugins.php @@ -17,6 +17,7 @@ use Grav\Common\File\CompiledYamlFile; use Grav\Events\PluginsLoadedEvent; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use RuntimeException; +use SplFileInfo; use Symfony\Component\EventDispatcher\EventDispatcher; use function get_class; use function is_object; @@ -27,7 +28,7 @@ use function is_object; */ class Plugins extends Iterator { - /** @var array */ + /** @var array|null */ public $formFieldTypes; /** @var bool */ @@ -46,6 +47,7 @@ class Plugins extends Iterator $iterator = $locator->getIterator('plugins://'); $plugins = []; + /** @var SplFileInfo $directory */ foreach ($iterator as $directory) { if (!$directory->isDir()) { continue; @@ -56,7 +58,10 @@ class Plugins extends Iterator sort($plugins, SORT_NATURAL | SORT_FLAG_CASE); foreach ($plugins as $plugin) { - $this->add($this->loadPlugin($plugin)); + $object = $this->loadPlugin($plugin); + if ($object) { + $this->add($object); + } } } @@ -68,13 +73,21 @@ class Plugins extends Iterator $blueprints = []; $formFields = []; + $grav = Grav::instance(); + + /** @var Config $config */ + $config = $grav['config']; + /** @var Plugin $plugin */ foreach ($this->items as $plugin) { - if (isset($plugin->features['blueprints'])) { - $blueprints["plugin://{$plugin->name}/blueprints"] = $plugin->features['blueprints']; - } - if (method_exists($plugin, 'getFormFieldTypes')) { - $formFields[get_class($plugin)] = isset($plugin->features['formfields']) ? $plugin->features['formfields'] : 0; + // Setup only enabled plugins. + if ($config["plugins.{$plugin->name}.enabled"] && $plugin instanceof Plugin) { + if (isset($plugin->features['blueprints'])) { + $blueprints["plugin://{$plugin->name}/blueprints"] = $plugin->features['blueprints']; + } + if (method_exists($plugin, 'getFormFieldTypes')) { + $formFields[get_class($plugin)] = $plugin->features['formfields'] ?? 0; + } } } @@ -83,7 +96,7 @@ class Plugins extends Iterator arsort($blueprints, SORT_NUMERIC); /** @var UniformResourceLocator $locator */ - $locator = Grav::instance()['locator']; + $locator = $grav['locator']; $locator->addPath('blueprints', '', array_keys($blueprints), ['system', 'blueprints']); } @@ -150,6 +163,7 @@ class Plugins extends Iterator * Add a plugin * * @param Plugin $plugin + * @return void */ public function add($plugin) { @@ -175,8 +189,8 @@ class Plugins extends Iterator */ public static function getPlugins(): array { - $grav = Grav::instance(); - $plugins = $grav['plugins']; + /** @var Plugins $plugins */ + $plugins = Grav::instance()['plugins']; $list = []; foreach ($plugins as $instance) { @@ -200,11 +214,13 @@ class Plugins extends Iterator /** * Return list of all plugin data with their blueprints. * - * @return array + * @return Data[] */ public static function all() { $grav = Grav::instance(); + + /** @var Plugins $plugins */ $plugins = $grav['plugins']; $list = []; diff --git a/system/src/Grav/Common/Processors/InitializeProcessor.php b/system/src/Grav/Common/Processors/InitializeProcessor.php index a6a606c..ea23fa8 100644 --- a/system/src/Grav/Common/Processors/InitializeProcessor.php +++ b/system/src/Grav/Common/Processors/InitializeProcessor.php @@ -105,8 +105,9 @@ class InitializeProcessor extends ProcessorBase $this->initializeUri($config); // Grav may return redirect response right away. - if ($config->get('system.pages.redirect_trailing_slash', false)) { - $response = $this->handleRedirectRequest($request); + $redirectCode = (int)$config->get('system.pages.redirect_trailing_slash', 1); + if ($redirectCode) { + $response = $this->handleRedirectRequest($request, $redirectCode > 300 ? $redirectCode : null); if ($response) { $this->stopTimer('_init'); @@ -413,7 +414,7 @@ class InitializeProcessor extends ProcessorBase $this->stopTimer('_init_uri'); } - protected function handleRedirectRequest(RequestInterface $request): ?ResponseInterface + protected function handleRedirectRequest(RequestInterface $request, int $code = null): ?ResponseInterface { if (!in_array($request->getMethod(), ['GET', 'HEAD'])) { return null; @@ -426,7 +427,7 @@ class InitializeProcessor extends ProcessorBase if ($path !== $root && $path !== $root . '/' && Utils::endsWith($path, '/')) { // Use permanent redirect for SEO reasons. - return $this->container->getRedirectResponse((string)$uri->withPath(rtrim($path, '/')), 301); + return $this->container->getRedirectResponse((string)$uri->withPath(rtrim($path, '/')), $code); } return null; diff --git a/system/src/Grav/Common/Service/PagesServiceProvider.php b/system/src/Grav/Common/Service/PagesServiceProvider.php index 4acf370..55f6a45 100644 --- a/system/src/Grav/Common/Service/PagesServiceProvider.php +++ b/system/src/Grav/Common/Service/PagesServiceProvider.php @@ -77,32 +77,46 @@ class PagesServiceProvider implements ServiceProviderInterface } } - $url = $pages->route($page->route()); + $route = $page->route(); + if ($route && \in_array($uri->method(), ['GET', 'HEAD'], true)) { + $pageExtension = $page->urlExtension(); + $url = $pages->route($route) . $pageExtension; - if ($uri->params()) { - if ($url === '/') { //Avoid double slash - $url = $uri->params(); - } else { - $url .= $uri->params(); + if ($uri->params()) { + if ($url === '/') { //Avoid double slash + $url = $uri->params(); + } else { + $url .= $uri->params(); + } + } + if ($uri->query()) { + $url .= '?' . $uri->query(); + } + if ($uri->fragment()) { + $url .= '#' . $uri->fragment(); } - } - if ($uri->query()) { - $url .= '?' . $uri->query(); - } - if ($uri->fragment()) { - $url .= '#' . $uri->fragment(); - } - /** @var Language $language */ - $language = $grav['language']; + /** @var Language $language */ + $language = $grav['language']; - // Language-specific redirection scenarios - if ($language->enabled() && ($language->isLanguageInUrl() xor $language->isIncludeDefaultLanguage())) { - $grav->redirect($url); - } - // Default route test and redirect - if ($config->get('system.pages.redirect_default_route') && $page->route() !== $path) { - $grav->redirect($url); + $redirectCode = (int)$config->get('system.pages.redirect_default_route', 0); + + // Language-specific redirection scenarios + if ($language->enabled() && ($language->isLanguageInUrl() xor $language->isIncludeDefaultLanguage())) { + $grav->redirect($url, $redirectCode); + } + + // Default route test and redirect + if ($redirectCode) { + $uriExtension = $uri->extension(); + $uriExtension = null !== $uriExtension ? '.' . $uriExtension : ''; + + if ($route !== $path || ($pageExtension !== $uriExtension + && \in_array($pageExtension, ['', '.htm', '.html'], true) + && \in_array($uriExtension, ['', '.htm', '.html'], true))) { + $grav->redirect($url, $redirectCode); + } + } } } diff --git a/system/src/Grav/Common/Theme.php b/system/src/Grav/Common/Theme.php index 2b807b6..a5006a2 100644 --- a/system/src/Grav/Common/Theme.php +++ b/system/src/Grav/Common/Theme.php @@ -9,9 +9,9 @@ namespace Grav\Common; -use Grav\Common\Page\Interfaces\PageInterface; use Grav\Common\Config\Config; use RocketTheme\Toolbox\File\YamlFile; +use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; /** * Class Theme @@ -44,53 +44,30 @@ class Theme extends Plugin /** * Persists to disk the theme parameters currently stored in the Grav Config object * - * @param string $theme_name The name of the theme whose config it should store. + * @param string $name The name of the theme whose config it should store. * @return bool */ - public static function saveConfig($theme_name) + public static function saveConfig($name) { - if (!$theme_name) { + if (!$name) { return false; } $grav = Grav::instance(); + + /** @var UniformResourceLocator $locator */ $locator = $grav['locator']; - $filename = 'config://themes/' . $theme_name . '.yaml'; - $file = YamlFile::instance($locator->findResource($filename, true, true)); - $content = $grav['config']->get('themes.' . $theme_name); + + $filename = 'config://themes/' . $name . '.yaml'; + $file = YamlFile::instance((string)$locator->findResource($filename, true, true)); + $content = $grav['config']->get('themes.' . $name); $file->save($content); $file->free(); + unset($file); return true; } - /** - * Override the mergeConfig method to work for themes - * - * @param PageInterface $page - * @param string $deep - * @param array $params - * @param string $type - * @return Data\Data - */ - protected function mergeConfig(PageInterface $page, $deep = 'merge', $params = [], $type = 'themes') - { - return parent::mergeConfig($page, $deep, $params, $type); - } - - /** - * Simpler getter for the theme blueprint - * - * @return mixed - */ - public function getBlueprint() - { - if (!$this->blueprint) { - $this->loadBlueprint(); - } - return $this->blueprint; - } - /** * Load blueprints. * @@ -100,8 +77,11 @@ class Theme extends Plugin { if (!$this->blueprint) { $grav = Grav::instance(); + /** @var Themes $themes */ $themes = $grav['themes']; - $this->blueprint = $themes->get($this->name)->blueprints(); + $data = $themes->get($this->name); + \assert($data !== null); + $this->blueprint = $data->blueprints(); } } } diff --git a/system/src/Grav/Common/Themes.php b/system/src/Grav/Common/Themes.php index 6adeea0..bf155ed 100644 --- a/system/src/Grav/Common/Themes.php +++ b/system/src/Grav/Common/Themes.php @@ -33,10 +33,8 @@ class Themes extends Iterator { /** @var Grav */ protected $grav; - /** @var Config */ protected $config; - /** @var bool */ protected $inited = false; @@ -95,6 +93,20 @@ class Themes extends Iterator $events->addSubscriber($instance); } + // Register blueprints. + if (is_dir('theme://blueprints/pages')) { + /** @var UniformResourceLocator $locator */ + $locator = $this->grav['locator']; + $locator->addPath('blueprints', '', ['theme://blueprints'], ['user', 'blueprints']); + } + + // Register form fields. + if (method_exists($instance, 'getFormFieldTypes')) { + /** @var Plugins $plugins */ + $plugins = $this->grav['plugins']; + $plugins->formFieldTypes = $instance->getFormFieldTypes() + $plugins->formFieldTypes; + } + $this->grav['theme'] = $instance; $this->grav->fireEvent('onThemeInitialized'); @@ -382,7 +394,10 @@ class Themes extends Iterator } // Try Old style theme classes - $path = strtolower(preg_replace('#\\\|_(?!.+\\\)#', '/', $class)); + $path = preg_replace('#\\\|_(?!.+\\\)#', '/', $class); + \assert(null !== $path); + + $path = strtolower($path); $file = $locator("themes://{$path}/theme.php") ?: $locator("themes://{$path}/{$path}.php"); // Load class diff --git a/system/src/Grav/Common/Uri.php b/system/src/Grav/Common/Uri.php index dd98b16..22f6b86 100644 --- a/system/src/Grav/Common/Uri.php +++ b/system/src/Grav/Common/Uri.php @@ -21,6 +21,7 @@ use RocketTheme\Toolbox\Event\Event; use RuntimeException; use function array_key_exists; use function count; +use function in_array; use function is_array; use function is_string; use function strlen; @@ -394,7 +395,7 @@ class Uri * Return the Extension of the URI * * @param string|null $default - * @return string The extension of the URI + * @return string|null The extension of the URI */ public function extension($default = null) { @@ -1408,18 +1409,14 @@ class Uri /** * Check if this is a valid Grav extension * - * @param string $extension + * @param string|null $extension * @return bool */ - public function isValidExtension($extension) + public function isValidExtension($extension): bool { - $valid_page_types = implode('|', Utils::getSupportPageTypes()); + $extension = (string)$extension; - // Strip the file extension for valid page types - if (preg_match('/(' . $valid_page_types . ')/', $extension)) { - return true; - } - return false; + return $extension !== '' && in_array($extension, Utils::getSupportPageTypes(), true); } /** diff --git a/system/src/Grav/Console/Cli/CleanCommand.php b/system/src/Grav/Console/Cli/CleanCommand.php index 8aa019c..b0c9499 100644 --- a/system/src/Grav/Console/Cli/CleanCommand.php +++ b/system/src/Grav/Console/Cli/CleanCommand.php @@ -154,8 +154,6 @@ class CleanCommand extends Command 'vendor/itsgoingd/clockwork/.gitattributes', 'vendor/itsgoingd/clockwork/CHANGELOG.md', 'vendor/itsgoingd/clockwork/composer.json', - 'vendor/kodus/psr7-server/composer.json', - 'vendor/kodus/psr7-server/CHANGELOG.md', 'vendor/league/climate/composer.json', 'vendor/league/climate/CHANGELOG.md', 'vendor/league/climate/CONTRIBUTING.md', @@ -197,6 +195,9 @@ class CleanCommand extends Command 'vendor/nyholm/psr7/phpstan.neon.dist', 'vendor/nyholm/psr7/CHANGELOG.md', 'vendor/nyholm/psr7/psalm.xml', + 'vendor/nyholm/psr7-server/.github', + 'vendor/nyholm/psr7-server/composer.json', + 'vendor/nyholm/psr7-server/CHANGELOG.md', 'vendor/phive/twig-extensions-deferred/.gitignore', 'vendor/phive/twig-extensions-deferred/.travis.yml', 'vendor/phive/twig-extensions-deferred/composer.json', diff --git a/system/src/Grav/Framework/Controller/Traits/ControllerResponseTrait.php b/system/src/Grav/Framework/Controller/Traits/ControllerResponseTrait.php index 1c9181b..bbc8f1a 100644 --- a/system/src/Grav/Framework/Controller/Traits/ControllerResponseTrait.php +++ b/system/src/Grav/Framework/Controller/Traits/ControllerResponseTrait.php @@ -14,11 +14,13 @@ namespace Grav\Framework\Controller\Traits; use Grav\Common\Config\Config; use Grav\Common\Debugger; use Grav\Common\Grav; +use Grav\Common\Utils; use Grav\Framework\Psr7\Response; use Grav\Framework\RequestHandler\Exception\RequestException; use Grav\Framework\Route\Route; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\StreamInterface; use Throwable; use function get_class; use function in_array; @@ -76,6 +78,55 @@ trait ControllerResponseTrait return new Response($code, $headers, json_encode($content)); } + /** + * @param string $filename + * @param string|resource|StreamInterface $resource + * @param array|null $headers + * @param array|null $options + * @return ResponseInterface + */ + protected function createDownloadResponse(string $filename, $resource, array $headers = null, array $options = null): ResponseInterface + { + // Required for IE, otherwise Content-Disposition may be ignored + if (ini_get('zlib.output_compression')) { + @ini_set('zlib.output_compression', 'Off'); + } + + $headers = $headers ?? []; + $options = $options ?? ['force_download' => true]; + + $file_parts = pathinfo($filename); + + if (!isset($headers['Content-Type'])) { + $mimetype = Utils::getMimeByExtension($file_parts['extension']); + + $headers['Content-Type'] = $mimetype; + } + + // TODO: add multipart download support. + //$headers['Accept-Ranges'] = 'bytes'; + + if (!empty($options['force_download'])) { + $headers['Content-Disposition'] = 'attachment; filename="' . $file_parts['basename'] . '"'; + } + + if (!isset($headers['Content-Length'])) { + $realpath = realpath($filename); + if ($realpath) { + $headers['Content-Length'] = filesize($realpath); + } + } + + $headers += [ + 'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT', + 'Last-Modified' => gmdate('D, d M Y H:i:s') . ' GMT', + 'Cache-Control' => 'no-store, no-cache, must-revalidate', + 'Pragma' => 'no-cache' + ]; + + return new Response(200, $headers, $resource); + } + /** * @param string $url * @param int|null $code diff --git a/system/src/Grav/Framework/Flex/FlexIndex.php b/system/src/Grav/Framework/Flex/FlexIndex.php index 98f6c8b..d480bc9 100644 --- a/system/src/Grav/Framework/Flex/FlexIndex.php +++ b/system/src/Grav/Framework/Flex/FlexIndex.php @@ -380,7 +380,7 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde // Handle primary key alias. $keyField = $this->getFlexDirectory()->getStorage()->getKeyField(); - if (isset($orderings[$keyField])) { + if ($keyField !== 'key' && $keyField !== 'storage_key' && isset($orderings[$keyField])) { $orderings['key'] = $orderings[$keyField]; unset($orderings[$keyField]); } diff --git a/system/src/Grav/Framework/Flex/FlexObject.php b/system/src/Grav/Framework/Flex/FlexObject.php index 9011745..09c5638 100644 --- a/system/src/Grav/Framework/Flex/FlexObject.php +++ b/system/src/Grav/Framework/Flex/FlexObject.php @@ -885,6 +885,14 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface ]; } + /** + * Clone object. + */ + public function __clone() + { + // Allows future compatibility as parent::__clone() works. + } + protected function markAsCopy(): void { $meta = $this->getMetaData(); diff --git a/system/src/Grav/Framework/Flex/Pages/FlexPageObject.php b/system/src/Grav/Framework/Flex/Pages/FlexPageObject.php index 09f9e60..621dae0 100644 --- a/system/src/Grav/Framework/Flex/Pages/FlexPageObject.php +++ b/system/src/Grav/Framework/Flex/Pages/FlexPageObject.php @@ -16,7 +16,6 @@ use Grav\Common\Grav; use Grav\Common\Page\Interfaces\PageInterface; use Grav\Common\Page\Traits\PageFormTrait; use Grav\Common\User\Interfaces\UserCollectionInterface; -use Grav\Framework\File\Formatter\YamlFormatter; use Grav\Framework\Flex\FlexObject; use Grav\Framework\Flex\Interfaces\FlexObjectInterface; use Grav\Framework\Flex\Interfaces\FlexTranslateInterface; @@ -50,6 +49,20 @@ class FlexPageObject extends FlexObject implements PageInterface, FlexTranslateI /** @var array|null */ protected $_reorder; + /** @var FlexPageObject|null */ + protected $_original; + + /** + * Clone page. + */ + public function __clone() + { + parent::__clone(); + + if (isset($this->header)) { + $this->header = clone($this->header); + } + } /** * @return array @@ -242,6 +255,32 @@ class FlexPageObject extends FlexObject implements PageInterface, FlexTranslateI return parent::save(); } + /** + * Gets the Page Unmodified (original) version of the page. + * + * Assumes that object has been cloned before modifying it. + * + * @return FlexPageObject|null The original version of the page. + */ + public function getOriginal() + { + return $this->_original; + } + + /** + * Store the Page Unmodified (original) version of the page. + * + * Can be called multiple times, only the first call matters. + * + * @return void + */ + public function storeOriginal(): void + { + if (null === $this->_original) { + $this->_original = clone $this; + } + } + /** * Get display order for the associated media. * @@ -398,23 +437,6 @@ class FlexPageObject extends FlexObject implements PageInterface, FlexTranslateI unset($elements['content']); } - // TODO: Remove: RAW frontmatter support has been moved to Flex-Objects v1.0.2 controller. - if (isset($elements['frontmatter'])) { - $formatter = new YamlFormatter(); - try { - // Replace the whole header except for media order, which is used in admin. - $media_order = $elements['media_order'] ?? null; - $elements['header'] = $formatter->decode($elements['frontmatter']); - if ($media_order) { - $elements['header']['media_order'] = $media_order; - } - } catch (RuntimeException $e) { - throw new RuntimeException('Badly formatted markdown'); - } - - unset($elements['frontmatter']); - } - if (!$extended) { $folder = !empty($elements['folder']) ? trim($elements['folder']) : ''; diff --git a/system/src/Grav/Framework/Flex/Pages/Traits/PageAuthorsTrait.php b/system/src/Grav/Framework/Flex/Pages/Traits/PageAuthorsTrait.php index d7af40f..5d3e968 100644 --- a/system/src/Grav/Framework/Flex/Pages/Traits/PageAuthorsTrait.php +++ b/system/src/Grav/Framework/Flex/Pages/Traits/PageAuthorsTrait.php @@ -27,6 +27,8 @@ trait PageAuthorsTrait { /** @var array */ private $_authors; + /** @var array|null */ + private $_permissionsCache; /** * Returns true if object has the named author. @@ -70,15 +72,19 @@ trait PageAuthorsTrait */ public function getPermissions(bool $inherit = false) { - $permissions = []; - if ($inherit && $this->getNestedProperty('header.permissions.inherit', true)) { - $parent = $this->parent(); - if ($parent && method_exists($parent, 'getPermissions')) { - $permissions = $parent->getPermissions($inherit); + if (null === $this->_permissionsCache) { + $permissions = []; + if ($inherit && $this->getNestedProperty('header.permissions.inherit', true)) { + $parent = $this->parent(); + if ($parent && method_exists($parent, 'getPermissions')) { + $permissions = $parent->getPermissions($inherit); + } } + + $this->_permissionsCache = $this->loadPermissions($permissions); } - return $this->loadPermissions($permissions); + return $this->_permissionsCache; } /** diff --git a/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php b/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php index ba81d8f..1c32bf5 100644 --- a/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php +++ b/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php @@ -277,6 +277,8 @@ trait PageLegacyTrait throw new RuntimeException('Failed: Cannot set page parent to a child of current page'); } + $this->storeOriginal(); + // TODO: throw new RuntimeException(__METHOD__ . '(): Not Implemented'); } @@ -292,6 +294,8 @@ trait PageLegacyTrait */ public function copy(PageInterface $parent = null) { + $this->storeOriginal(); + $filesystem = Filesystem::getInstance(false); $parentStorageKey = ltrim($filesystem->dirname("/{$this->getMasterKey()}"), '/'); @@ -715,8 +719,9 @@ trait PageLegacyTrait /** @var UniformResourceLocator $locator */ $locator = Grav::instance()['locator']; + $folder = $locator->isStream($folder) ? $locator->getResource($folder) : GRAV_ROOT . "/{$folder}"; - return $locator->findResource($folder, true, true) . '/' . ($this->isPage() ? $this->name() : 'default.md'); + return $folder . '/' . ($this->isPage() ? $this->name() : 'default.md'); } /** @@ -733,8 +738,9 @@ trait PageLegacyTrait /** @var UniformResourceLocator $locator */ $locator = Grav::instance()['locator']; + $folder = $locator->isStream($folder) ? $locator->getResource($folder, false) : $folder; - return $locator->findResource($folder, false, true) . '/' . ($this->isPage() ? $this->name() : 'default.md'); + return $folder . '/' . ($this->isPage() ? $this->name() : 'default.md'); } /** @@ -1085,18 +1091,6 @@ trait PageLegacyTrait return $this->exists() || is_dir($this->getStorageFolder() ?? ''); } - /** - * Gets the Page Unmodified (original) version of the page. - * - * Assumes that object has been cloned before modifying it. - * - * @return PageInterface|null The original version of the page. - */ - public function getOriginal() - { - return $this->getFlexDirectory()->getObject($this->getKey()); - } - /** * Gets the action. * diff --git a/system/src/Grav/Framework/Flex/Pages/Traits/PageRoutableTrait.php b/system/src/Grav/Framework/Flex/Pages/Traits/PageRoutableTrait.php index 0029739..b2be4ee 100644 --- a/system/src/Grav/Framework/Flex/Pages/Traits/PageRoutableTrait.php +++ b/system/src/Grav/Framework/Flex/Pages/Traits/PageRoutableTrait.php @@ -18,6 +18,7 @@ use Grav\Common\Uri; use Grav\Framework\Filesystem\Filesystem; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use RuntimeException; +use function dirname; use function is_string; /** @@ -32,6 +33,8 @@ trait PageRoutableTrait private $_route; /** @var string|null */ private $_path; + /** @var PageInterface|null */ + private $_parentCache; /** * Returns the page extension, got from the page `url_extension` config and falls back to the @@ -317,7 +320,7 @@ trait PageRoutableTrait /** @var UniformResourceLocator $locator */ $locator = Grav::instance()['locator']; - $path = $locator->findResource($folder, false); + $path = $locator->isStream($folder) ? $locator->findResource($folder, false) : $folder; return is_string($path) ? $path : null; } @@ -350,7 +353,7 @@ trait PageRoutableTrait if ($folder) { /** @var UniformResourceLocator $locator */ $locator = Grav::instance()['locator']; - $folder = $locator($folder); + $folder = $locator->isStream($folder) ? $locator->getResource($folder) : GRAV_ROOT . "/{$folder}"; } return $this->_path = is_string($folder) ? $folder : null; @@ -413,13 +416,12 @@ trait PageRoutableTrait throw new RuntimeException(__METHOD__ . '(PageInterface): Not Implemented'); } - if ($this->root()) { - return null; + if ($this->_parentCache || $this->root()) { + return $this->_parentCache; } - $filesystem = Filesystem::getInstance(false); $directory = $this->getFlexDirectory(); - $parentKey = ltrim($filesystem->dirname("/{$this->getKey()}"), '/'); + $parentKey = ltrim(dirname("/{$this->getKey()}"), '/'); if ($parentKey) { $parent = $directory->getObject($parentKey); $language = $this->getLanguage(); @@ -427,12 +429,14 @@ trait PageRoutableTrait $parent = $parent->getTranslation($language) ?? $parent; } - return $parent; + $this->_parentCache = $parent; + } else { + $index = $directory->getIndex(); + + $this->_parentCache = method_exists($index, 'getRoot') ? $index->getRoot() : null; } - $index = $directory->getIndex(); - - return method_exists($index, 'getRoot') ? $index->getRoot() : null; + return $this->_parentCache; } /** diff --git a/system/src/Grav/Framework/Flex/Storage/AbstractFilesystemStorage.php b/system/src/Grav/Framework/Flex/Storage/AbstractFilesystemStorage.php index 97384ab..1934f50 100644 --- a/system/src/Grav/Framework/Flex/Storage/AbstractFilesystemStorage.php +++ b/system/src/Grav/Framework/Flex/Storage/AbstractFilesystemStorage.php @@ -186,10 +186,10 @@ abstract class AbstractFilesystemStorage implements FlexStorageInterface $locator = Grav::instance()['locator']; if (!$locator->isStream($path)) { - return $path; + return GRAV_ROOT . "/{$path}"; } - return (string)($locator->findResource($path) ?: $locator->findResource($path, true, true)); + return $locator->getResource($path); } /** diff --git a/system/src/Grav/Framework/Flex/Storage/FileStorage.php b/system/src/Grav/Framework/Flex/Storage/FileStorage.php index 2dc0757..eabd658 100644 --- a/system/src/Grav/Framework/Flex/Storage/FileStorage.php +++ b/system/src/Grav/Framework/Flex/Storage/FileStorage.php @@ -83,6 +83,8 @@ class FileStorage extends FolderStorage $path = $this->getPathFromKey($src); $file = $this->getFile($path); $file->delete(); + $file->free(); + unset($file); return true; } diff --git a/system/src/Grav/Framework/Flex/Storage/FolderStorage.php b/system/src/Grav/Framework/Flex/Storage/FolderStorage.php index acdab78..229194d 100644 --- a/system/src/Grav/Framework/Flex/Storage/FolderStorage.php +++ b/system/src/Grav/Framework/Flex/Storage/FolderStorage.php @@ -377,12 +377,14 @@ class FolderStorage extends AbstractFilesystemStorage $file = $this->getFile($path); try { $data = (array)$file->content(); - $file->free(); if (isset($data[0])) { throw new RuntimeException('Broken object file'); } } catch (RuntimeException $e) { $data = ['__ERROR' => $e->getMessage()]; + } finally { + $file->free(); + unset($file); } $data['__META'] = $this->getObjectMeta($key); @@ -426,13 +428,17 @@ class FolderStorage extends AbstractFilesystemStorage $file->save($row); - /** @var UniformResourceLocator $locator */ - $locator = Grav::instance()['locator']; - if ($locator->isStream($path)) { - $locator->clearCache(); - } } catch (RuntimeException $e) { throw new RuntimeException(sprintf('Flex saveFile(%s): %s', $path ?? $key, $e->getMessage())); + } finally { + /** @var UniformResourceLocator $locator */ + $locator = Grav::instance()['locator']; + $locator->clearCache(); + + if (isset($file)) { + $file->free(); + unset($file); + } } $row['__META'] = $this->getObjectMeta($key, true); @@ -452,14 +458,14 @@ class FolderStorage extends AbstractFilesystemStorage if ($file->exists()) { $file->delete(); } - - /** @var UniformResourceLocator $locator */ - $locator = Grav::instance()['locator']; - if ($locator->isStream($filename)) { - $locator->clearCache($filename); - } } catch (RuntimeException $e) { throw new RuntimeException(sprintf('Flex deleteFile(%s): %s', $filename, $e->getMessage())); + } finally { + /** @var UniformResourceLocator $locator */ + $locator = Grav::instance()['locator']; + $locator->clearCache(); + + $file->free(); } return $data; @@ -474,14 +480,12 @@ class FolderStorage extends AbstractFilesystemStorage { try { Folder::copy($this->resolvePath($src), $this->resolvePath($dst)); - - /** @var UniformResourceLocator $locator */ - $locator = Grav::instance()['locator']; - if ($locator->isStream($src) || $locator->isStream($dst)) { - $locator->clearCache(); - } } catch (RuntimeException $e) { throw new RuntimeException(sprintf('Flex copyFolder(%s, %s): %s', $src, $dst, $e->getMessage())); + } finally { + /** @var UniformResourceLocator $locator */ + $locator = Grav::instance()['locator']; + $locator->clearCache(); } return true; @@ -496,14 +500,12 @@ class FolderStorage extends AbstractFilesystemStorage { try { Folder::move($this->resolvePath($src), $this->resolvePath($dst)); - - /** @var UniformResourceLocator $locator */ - $locator = Grav::instance()['locator']; - if ($locator->isStream($src) || $locator->isStream($dst)) { - $locator->clearCache(); - } } catch (RuntimeException $e) { throw new RuntimeException(sprintf('Flex moveFolder(%s, %s): %s', $src, $dst, $e->getMessage())); + } finally { + /** @var UniformResourceLocator $locator */ + $locator = Grav::instance()['locator']; + $locator->clearCache(); } return true; @@ -517,17 +519,13 @@ class FolderStorage extends AbstractFilesystemStorage protected function deleteFolder(string $path, bool $include_target = false): bool { try { - $success = Folder::delete($this->resolvePath($path), $include_target); - - /** @var UniformResourceLocator $locator */ - $locator = Grav::instance()['locator']; - if ($locator->isStream($path)) { - $locator->clearCache(); - } - - return $success; + return Folder::delete($this->resolvePath($path), $include_target); } catch (RuntimeException $e) { throw new RuntimeException(sprintf('Flex deleteFolder(%s): %s', $path, $e->getMessage())); + } finally { + /** @var UniformResourceLocator $locator */ + $locator = Grav::instance()['locator']; + $locator->clearCache(); } } @@ -669,7 +667,14 @@ class FolderStorage extends AbstractFilesystemStorage /** @var string $pattern */ $pattern = !empty($options['pattern']) ? $options['pattern'] : $this->dataPattern; - $this->dataFolder = $options['folder']; + /** @var UniformResourceLocator $locator */ + $locator = Grav::instance()['locator']; + $folder = $options['folder']; + if ($locator->isStream($folder)) { + $folder = $locator->getResource($folder, false); + } + + $this->dataFolder = $folder; $this->dataFile = $options['file'] ?? 'item'; $this->dataExt = $extension; if (mb_strpos($pattern, '{FILE}') === false && mb_strpos($pattern, '{EXT}') === false) { diff --git a/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php b/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php index df889ce..85c1429 100644 --- a/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php +++ b/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php @@ -414,9 +414,13 @@ class SimpleStorage extends AbstractFilesystemStorage } $file->save($content); $this->modified = (int)$file->modified(); // cast false to 0 - $file->free(); } catch (RuntimeException $e) { throw new RuntimeException(sprintf('Flex save(): %s', $e->getMessage())); + } finally { + if (isset($file)) { + $file->free(); + unset($file); + } } } @@ -453,6 +457,10 @@ class SimpleStorage extends AbstractFilesystemStorage $data = new Data($content); $content = $data->get($this->prefix); } + + $file->free(); + unset($file); + $this->data = $content; $list = []; diff --git a/tmp/forms/fg86637jgl2sbvcbloavimfam4/73f35c84f67d9518064f6783910db89a/index.yaml b/tmp/forms/fg86637jgl2sbvcbloavimfam4/73f35c84f67d9518064f6783910db89a/index.yaml deleted file mode 100644 index d7eca55..0000000 --- a/tmp/forms/fg86637jgl2sbvcbloavimfam4/73f35c84f67d9518064f6783910db89a/index.yaml +++ /dev/null @@ -1,87 +0,0 @@ -form: flex-pages -unique_id: 73f35c84f67d9518064f6783910db89a -url: 'http://localhost:8000/admin/pages/gouvernance/conseil-dadministration/presidente-du-conseil-dadministration/membres-du-conseil-dadministration' -user: - username: admin - email: ouidade@figureslibres.io -timestamps: - created: 1614952271 - updated: 1614952271 -data: - header: - title: 'Membres du conseil d''administration' - media_order: null - body_classes: null - order_by: null - order_manual: null - published: null - date: null - publish_date: null - unpublish_date: null - metadata: null - taxonomy: null - dateformat: null - menu: null - slug: null - redirect: null - process: null - twig_first: null - never_cache_twig: null - child_type: null - routable: null - cache_enable: null - visible: null - debugger: null - template: null - append_url_extension: null - routes: - default: null - canonical: null - aliases: null - admin: - children_display_order: null - login: - visibility_requires_access: null - access: null - permissions: - inherit: null - authors: null - groups: null - content: "# Jean-Baptiste Butlen\r\nSous-directeur Aménagement\r\ndurable, Direction Générale de\r\nl’Aménagement, du Logement\r\net de la Nature, Ministère de la\r\nTransition écologique, Ministère\r\nde la Cohésion des territoires et\r\ndes Relations avec les\r\nCollectivités territoriales\r\n" - folder: membres-du-conseil-dadministration - route: /gouvernance/conseil-dadministration/presidente-du-conseil-dadministration/membres-du-conseil-dadministration - name: default - ordering: false - order: null - blueprint: null - lang: null - xss_check: null - value: null - _post_entries_save: null -files: { } -object: - type: pages - key: gouvernance/conseil-dadministration/presidente-du-conseil-dadministration/membres-du-conseil-dadministration - storage_key: 03.gouvernance/01.conseil-dadministration/presidente-du-conseil-dadministration/membres-du-conseil-dadministration - timestamp: 1614952229 - serialized: - __META: - key: gouvernance/conseil-dadministration/presidente-du-conseil-dadministration/membres-du-conseil-dadministration - storage_key: 03.gouvernance/01.conseil-dadministration/presidente-du-conseil-dadministration/membres-du-conseil-dadministration - template: default - storage_timestamp: 1614952229 - markdown: - '': { default: 1614952229 } - checksum: 9a001ef28e8a20154a0f4f09a46ddebf - storage_key: 03.gouvernance/01.conseil-dadministration/presidente-du-conseil-dadministration/membres-du-conseil-dadministration - parent_key: 03.gouvernance/01.conseil-dadministration/presidente-du-conseil-dadministration - order: false - folder: membres-du-conseil-dadministration - template: default - lang: '' - header: - title: 'Membres du conseil d''administration' - root: false - markdown: "# Jean-Baptiste Butlen\nSous-directeur Aménagement\ndurable, Direction Générale de\nl’Aménagement, du Logement\net de la Nature, Ministère de la\nTransition écologique, Ministère\nde la Cohésion des territoires et\ndes Relations avec les\nCollectivités territoriales\n" - slug: membres-du-conseil-dadministration - name: default.md diff --git a/tmp/forms/fg86637jgl2sbvcbloavimfam4/ae2c7e0ffb4b4b1c4654412e6429a17c/index.yaml b/tmp/forms/fg86637jgl2sbvcbloavimfam4/ae2c7e0ffb4b4b1c4654412e6429a17c/index.yaml deleted file mode 100644 index 2dfdf60..0000000 --- a/tmp/forms/fg86637jgl2sbvcbloavimfam4/ae2c7e0ffb4b4b1c4654412e6429a17c/index.yaml +++ /dev/null @@ -1,29 +0,0 @@ -form: flex-pages -unique_id: ae2c7e0ffb4b4b1c4654412e6429a17c -url: '/pages/pr/:add' -user: - username: admin - email: ouidade@figureslibres.io -timestamps: - created: 1614944374 - updated: 1614944374 -data: null -files: { } -object: - type: pages - key: pr - storage_key: '' - timestamp: 0 - serialized: - __META: { } - storage_key: '' - parent_key: '' - order: '05.' - folder: pr - template: blog - lang: '' - root: false - route: / - name: blog - header: - title: Pr diff --git a/tmp/forms/fg86637jgl2sbvcbloavimfam4/b24e06058e6bf2c3e455378b84824a00/index.yaml b/tmp/forms/fg86637jgl2sbvcbloavimfam4/b24e06058e6bf2c3e455378b84824a00/index.yaml deleted file mode 100644 index 1e989de..0000000 --- a/tmp/forms/fg86637jgl2sbvcbloavimfam4/b24e06058e6bf2c3e455378b84824a00/index.yaml +++ /dev/null @@ -1,50 +0,0 @@ -form: flex-pages-raw -unique_id: b24e06058e6bf2c3e455378b84824a00 -url: 'http://localhost:8000/admin/pages/gouvernance-2' -user: - username: admin - email: ouidade@figureslibres.io -timestamps: - created: 1614944089 - updated: 1614944198 -data: - frontmatter: "---\r\ntitle: Gouvernance2\r\nmenu: GOUVERNANCE 2\r\nonpage_menu: true\r\nbody_classes: \"modular header-image fullwidth\"\r\n\r\ncontent:\r\n items: '@self.modular'\r\n order:\r\n by: default\r\n dir: asc\r\n custom:\r\n---" - content: null - ordering: true - folder: gouvernance-2 - route: null - name: modular - order: null - blueprint: null - xss_check: null - header: - media_order: null -files: { } -object: - type: pages - key: gouvernance-2 - storage_key: 04.gouvernance-2 - timestamp: 1614943947 - serialized: - __META: - key: gouvernance-2 - storage_key: 04.gouvernance-2 - template: modular - storage_timestamp: 1614943947 - markdown: - '': { modular: 1614943947 } - checksum: 430b1700b40c2bea498e6dc4ba633605 - storage_key: 04.gouvernance-2 - parent_key: '' - order: '04.' - folder: gouvernance-2 - template: modular - lang: '' - header: - title: Gouvernance-2 - content: - items: '@self.modular' - root: false - markdown: '' - slug: gouvernance-2 - name: modular.md diff --git a/tmp/forms/hajnagponl11621ppdikc5e6g4/c5c66e69061fcfcc38c77e522e153efe/index.yaml b/tmp/forms/hajnagponl11621ppdikc5e6g4/c5c66e69061fcfcc38c77e522e153efe/index.yaml deleted file mode 100644 index 10cd98d..0000000 --- a/tmp/forms/hajnagponl11621ppdikc5e6g4/c5c66e69061fcfcc38c77e522e153efe/index.yaml +++ /dev/null @@ -1,107 +0,0 @@ -form: flex-pages -unique_id: c5c66e69061fcfcc38c77e522e153efe -url: 'http://localhost:8000/admin/pages/home/_gouvernance-module' -user: - username: admin - email: ouidade@figureslibres.io -timestamps: - created: 1615559247 - updated: 1615559247 -data: - header: - title: Gouvernance - media_order: 'jeux-olypiques-paris-2024-village-athle-lot-e2.jpg,Logotype_GIP_EPAU.svg.png' - body_classes: 'modular fullwidth title-center title-h1h2' - menu: 'Gouvernance 2' - visible: true - debugger: true - admin: - children_display_order: collection - order_by: null - order_manual: null - onpage_menu: true - content: - items: '@self.modular' - order: - by: default - dir: asc - custom: [_conseil-dadministration_module] - published: null - date: null - publish_date: null - unpublish_date: null - metadata: null - taxonomy: null - dateformat: null - slug: null - redirect: null - process: null - twig_first: null - never_cache_twig: null - child_type: null - routable: null - cache_enable: null - template: null - append_url_extension: null - routes: - default: null - canonical: null - aliases: null - login: - visibility_requires_access: null - access: null - permissions: - inherit: null - authors: null - groups: null - content: '# Gouvernance' - folder: _gouvernance - route: /home - name: modular/gouvernance - ordering: true - order: '_accueil,_programmes,_rapports-dactivites,_gouvernance,_gouvernance,_contact' - blueprint: null - lang: null - xss_check: null - value: null - _post_entries_save: null -files: { } -object: - type: pages - key: home/_gouvernance-module - storage_key: 01.home/06._gouvernance-module - timestamp: 1615558956 - serialized: - __META: - key: home/_gouvernance-module - storage_key: 01.home/06._gouvernance-module - template: gouvernance - storage_timestamp: 1615558956 - markdown: - '': { gouvernance: 1615558685 } - children: - 01._conseil-dadministration_module: false - checksum: 7f21735022ad7faf780b47fe141b79e1 - storage_key: 01.home/06._gouvernance-module - parent_key: 01.home - order: '06.' - folder: _gouvernance-module - template: gouvernance - lang: '' - header: - title: 'gouvernance module' - menu: 'gouvernance module' - visible: true - onpage_menu: true - body_classes: 'modular fullwidth title-center title-h1h2' - content: - items: '@self.modular' - order: { by: default, dir: asc, custom: [_conseil-dadministration_module] } - media_order: 'jeux-olypiques-paris-2024-village-athle-lot-e2.jpg,Logotype_GIP_EPAU.svg.png' - admin: - children_display_order: collection - debugger: true - root: false - markdown: "gouvernance module\n" - slug: _gouvernance-module - name: gouvernance.md diff --git a/tmp/forms/m8co5qkkf12uur4tra88dbie5t/cdb3ae30b3dab66b186228ae772dd1a0/index.yaml b/tmp/forms/m8co5qkkf12uur4tra88dbie5t/cdb3ae30b3dab66b186228ae772dd1a0/index.yaml deleted file mode 100644 index 5555de7..0000000 --- a/tmp/forms/m8co5qkkf12uur4tra88dbie5t/cdb3ae30b3dab66b186228ae772dd1a0/index.yaml +++ /dev/null @@ -1,53 +0,0 @@ -form: flex-pages-raw -unique_id: cdb3ae30b3dab66b186228ae772dd1a0 -url: 'http://localhost:8000/admin/pages/programmes' -user: - username: admin - email: ouidade@figureslibres.io -timestamps: - created: 1614876264 - updated: 1614876264 -data: - frontmatter: "title: Gouvernance\r\ncontent:\r\n items: '@self.modular'\r\n" - content: null - ordering: true - folder: gouvernance - route: null - name: modular - order: 'home,gouvernance,gouvernance' - blueprint: null - xss_check: null - header: - media_order: null -files: { } -object: - type: pages - key: programmes - storage_key: 03.programmes - timestamp: 1614875485 - serialized: - __META: - key: programmes - storage_key: 03.programmes - template: modular - storage_timestamp: 1614875485 - markdown: - '': { modular: 1614875485 } - children: - _european: false - _popsu: false - checksum: 17d79b5a489014a479adac578c6eb693 - storage_key: 03.programmes - parent_key: '' - order: '03.' - folder: programmes - template: modular - lang: '' - header: - title: Gouvernance - content: - items: '@self.modular' - root: false - markdown: '' - slug: programmes - name: modular.md diff --git a/tmp/forms/m8co5qkkf12uur4tra88dbie5t/e75346bd00d0b9954ac33c8fde35d73f/index.yaml b/tmp/forms/m8co5qkkf12uur4tra88dbie5t/e75346bd00d0b9954ac33c8fde35d73f/index.yaml deleted file mode 100644 index 475786f..0000000 --- a/tmp/forms/m8co5qkkf12uur4tra88dbie5t/e75346bd00d0b9954ac33c8fde35d73f/index.yaml +++ /dev/null @@ -1,31 +0,0 @@ -form: flex-pages -unique_id: e75346bd00d0b9954ac33c8fde35d73f -url: '/pages/gouvernance/conseil-dadministration/_president/:add' -user: - username: admin - email: ouidade@figureslibres.io -timestamps: - created: 1614874025 - updated: 1614874025 -data: null -files: { } -object: - type: pages - key: gouvernance/conseil-dadministration/_president - storage_key: '' - timestamp: 0 - serialized: - __META: { } - storage_key: '' - parent_key: 03.gouvernance/01.conseil-dadministration - order: false - folder: _president - template: features - lang: '' - root: false - route: /gouvernance/conseil-dadministration - name: modular/features - modular: '1' - header: - title: president - body_classes: modular diff --git a/tmp/forms/oocdaafg1m81alcgel4g63t6cs/a44b13d8025f9fb13b03184c68bd181f/index.yaml b/tmp/forms/oocdaafg1m81alcgel4g63t6cs/a44b13d8025f9fb13b03184c68bd181f/index.yaml deleted file mode 100644 index ea61111..0000000 --- a/tmp/forms/oocdaafg1m81alcgel4g63t6cs/a44b13d8025f9fb13b03184c68bd181f/index.yaml +++ /dev/null @@ -1,84 +0,0 @@ -form: flex-pages-raw -unique_id: a44b13d8025f9fb13b03184c68bd181f -url: 'http://localhost:8000/admin/pages/id%C3%A9e%20page%20simple' -user: - username: admin - email: ouidade@figureslibres.io -timestamps: - created: 1615307485 - updated: 1615307507 -data: - header: - title: null - media_order: null - body_classes: null - visible: false - order_by: null - order_manual: null - published: null - date: null - publish_date: null - unpublish_date: null - metadata: null - taxonomy: null - dateformat: null - menu: null - slug: null - redirect: null - process: null - twig_first: null - never_cache_twig: null - child_type: null - routable: null - cache_enable: null - debugger: null - template: null - append_url_extension: null - routes: - default: null - canonical: null - aliases: null - admin: - children_display_order: null - login: - visibility_requires_access: null - access: null - permissions: - inherit: null - authors: null - groups: null - content: null - folder: 'idée page simple' - route: null - name: default - ordering: true - order: null - blueprint: null - lang: null - xss_check: null - value: null - _post_entries_save: null -files: { } -object: - type: pages - key: 'idée page simple' - storage_key: '02.idée page simple' - timestamp: 1615307353 - serialized: - __META: - key: 'idée page simple' - storage_key: '02.idée page simple' - template: null - storage_timestamp: 1615307353 - checksum: 8fd86ee78271bf8fc34c0683a71a03f6 - storage_key: '02.idée page simple' - parent_key: '' - order: '02.' - folder: 'idée page simple' - template: default - lang: '' - header: { } - root: false - markdown: '' - slug: 'idée page simple' - name: default.md diff --git a/tmp/forms/oocdaafg1m81alcgel4g63t6cs/e2b1fd25908ccd5d1621269a6a54fa1b/index.yaml b/tmp/forms/oocdaafg1m81alcgel4g63t6cs/e2b1fd25908ccd5d1621269a6a54fa1b/index.yaml deleted file mode 100644 index 1b02a01..0000000 --- a/tmp/forms/oocdaafg1m81alcgel4g63t6cs/e2b1fd25908ccd5d1621269a6a54fa1b/index.yaml +++ /dev/null @@ -1,29 +0,0 @@ -form: flex-pages -unique_id: e2b1fd25908ccd5d1621269a6a54fa1b -url: '/pages/gouvernanca/:add' -user: - username: admin - email: ouidade@figureslibres.io -timestamps: - created: 1615305090 - updated: 1615305090 -data: null -files: { } -object: - type: pages - key: gouvernanca - storage_key: '' - timestamp: 0 - serialized: - __META: { } - storage_key: '' - parent_key: '' - order: '02.' - folder: gouvernanca - template: default - lang: '' - root: false - route: / - name: default - header: - title: Gouvernanca diff --git a/tmp/forms/oocdaafg1m81alcgel4g63t6cs/f8b847bb606447afa42e342e90a112bf/index.yaml b/tmp/forms/oocdaafg1m81alcgel4g63t6cs/f8b847bb606447afa42e342e90a112bf/index.yaml deleted file mode 100644 index aeabca0..0000000 --- a/tmp/forms/oocdaafg1m81alcgel4g63t6cs/f8b847bb606447afa42e342e90a112bf/index.yaml +++ /dev/null @@ -1,31 +0,0 @@ -form: flex-pages -unique_id: f8b847bb606447afa42e342e90a112bf -url: '/pages/programmes/_european/:add' -user: - username: admin - email: ouidade@figureslibres.io -timestamps: - created: 1615304429 - updated: 1615304429 -data: null -files: { } -object: - type: pages - key: programmes/_european - storage_key: '' - timestamp: 0 - serialized: - __META: { } - storage_key: '' - parent_key: 02.programmes - order: false - folder: _european - template: features - lang: '' - root: false - route: /programmes - name: modular/features - modular: '1' - header: - title: European - body_classes: modular diff --git a/user/blueprints/pages/modular/programmes.yaml b/user/blueprints/pages/modular/programmes.yaml index b4f3dd9..a0215a5 100644 --- a/user/blueprints/pages/modular/programmes.yaml +++ b/user/blueprints/pages/modular/programmes.yaml @@ -43,6 +43,3 @@ form: .logo: type: file label: Logo - accept: - - image/* - - .svg diff --git a/user/config/site.yaml b/user/config/site.yaml index 35bdf6f..4c564d1 100644 --- a/user/config/site.yaml +++ b/user/config/site.yaml @@ -1,8 +1,8 @@ title: 'GIP EPAU' -default_lang: en +default_lang: fr author: - name: 'Joe Bloggs' - email: joe@example.com + name: 'Ouidade Soussi' + email: ouidade@figureslibres.io taxonomies: - category - tag diff --git a/user/config/system.yaml b/user/config/system.yaml index d51e045..d63c1dd 100644 --- a/user/config/system.yaml +++ b/user/config/system.yaml @@ -1,6 +1,5 @@ absolute_urls: false timezone: null -default_locale: null param_sep: ':' wrapped_site: false reverse_proxy_setup: false @@ -25,7 +24,6 @@ languages: session_store_active: false http_accept_language: false override_locale: false - content_fallback: { } pages_fallback_only: false home: alias: /home @@ -52,10 +50,10 @@ pages: page: true twig: true markdown: - extra: false - auto_line_breaks: false - auto_url_links: false - escape_markup: false + extra: true + auto_line_breaks: true + auto_url_links: true + escape_markup: true special_chars: '>': gt '<': lt @@ -79,9 +77,9 @@ pages: last_modified: false etag: true vary_accept_encoding: false - redirect_default_route: false redirect_default_code: '302' - redirect_trailing_slash: true + redirect_trailing_slash: 1 + redirect_default_route: 0 ignore_files: - .DS_Store ignore_folders: @@ -141,6 +139,7 @@ assets: js_pipeline_before_excludes: true js_minify: true enable_asset_timestamp: false + enable_asset_sri: false collections: jquery: 'system://assets/jquery/jquery-2.x.min.js' errors: @@ -163,7 +162,7 @@ images: cache_perms: '0755' debug: false auto_fix_orientation: true - seofriendly: false + seofriendly: true defaults: loading: auto media: diff --git a/user/pages/01.home/02._programmes/Europan France.jpg b/user/pages/01.home/02._programmes/europan_france.jpg similarity index 100% rename from user/pages/01.home/02._programmes/Europan France.jpg rename to user/pages/01.home/02._programmes/europan_france.jpg diff --git a/user/pages/01.home/02._programmes/POPSU2018_LOGO_moinsde6cm_sscartouche.png b/user/pages/01.home/02._programmes/popsu.png similarity index 100% rename from user/pages/01.home/02._programmes/POPSU2018_LOGO_moinsde6cm_sscartouche.png rename to user/pages/01.home/02._programmes/popsu.png diff --git a/user/pages/01.home/02._programmes/programmes.md b/user/pages/01.home/02._programmes/programmes.md index f9507eb..8f94c0f 100644 --- a/user/pages/01.home/02._programmes/programmes.md +++ b/user/pages/01.home/02._programmes/programmes.md @@ -7,21 +7,21 @@ programmes: nom_du_programme: POPSU texte_de_presentation: "Plateforme d’observation des projets et stratégies urbaine\_: Lieu de convergence des milieux de la recherche et de ceux qui font et gouvernent les villes, la Plateforme d’observation des projets et stratégies urbaines – **POPSU** – croise les savoirs scientifiques et l’expertise opérationnelle pour mieux comprendre les enjeux et les évolutions associés aux villes et aux territoires. _Elle capitalise, à des fins d’action, les connaissances établies sur les _métropoles et en assure la diffusion auprès de publics divers : professionnels, académiques, grand public... Lien vers le site\_: [popsu](http://www.popsu.archi.fr)" logo: - POPSU2018_LOGO_moinsde6cm_sscartouche.png: - name: POPSU2018_LOGO_moinsde6cm_sscartouche.png + popsu.png: + name: popsu.png type: image/png size: 22288 - path: POPSU2018_LOGO_moinsde6cm_sscartouche.png + path: popsu.png - icon: ;) nom_du_programme: Europan texte_de_presentation: 'Europan est un concours d’idées d’architecture et d’urbanisme se déroulant tous les deux ans simultanément dans une vingtaine de pays européens, sur un thème et un règlement communs. Dans chaque pays des sites sont proposés par des collectivités territoriales et leurs partenaires. Ce concours est suivi de réalisation in-situ pour les équipes sélectionnées. Europan facilite le dialogue sur les modes de faire la ville à toutes les échelles. https://www.europanfrance.org/' logo: - 'Europan France.jpg': - name: 'Europan France.jpg' + europan_france.jpg: + name: europan_france.jpg type: image/jpeg size: 41080 - path: 'Europan France.jpg' + path: europan_france.jpg - icon: null nom_du_programme: 'Forum des Solutions' @@ -39,6 +39,7 @@ programmes: logo: { } visible: true debugger: true +media_order: 'europan_france.jpg,popsu.png,forum_solution.png' --- # Programmes diff --git a/user/pages/01.home/04._gouvernance/02._equipe-epau/personnes.md b/user/pages/01.home/04._gouvernance/02._equipe-epau/personnes.md index ba8ad57..fe54684 100644 --- a/user/pages/01.home/04._gouvernance/02._equipe-epau/personnes.md +++ b/user/pages/01.home/04._gouvernance/02._equipe-epau/personnes.md @@ -1,11 +1,10 @@ --- -title: 'Équipe EPAU title' +title: 'Équipe EPAU' content: items: '@self.modular' visible: true debugger: true template: modular/personnes - body_classes: 'modular-row personnes' personnes: - diff --git a/user/themes/epau-antimatter/templates/modular/programmes.html.twig b/user/themes/epau-antimatter/templates/modular/programmes.html.twig index 47a2945..0839554 100644 --- a/user/themes/epau-antimatter/templates/modular/programmes.html.twig +++ b/user/themes/epau-antimatter/templates/modular/programmes.html.twig @@ -1,5 +1,6 @@
{{ content|raw }} + {{ dump(page.header) }}
{% for programme in page.header.programmes %}
@@ -16,10 +17,20 @@

{{ programme.texte_de_presentation }}

{% endif %} {% if programme.logo %} - “logo_programme” + logo_programme + + {% endif %}
{% endfor %}
+ + + +{# ça, ça marche mais maintenant faut créer un variable qui va chercher les images +{% if programme.logo %} +“logo_programme” +{% endif %} +#}