mirror of
https://github.com/getgrav/grav.git
synced 2025-12-05 15:29:57 +01:00
Compare commits
100 Commits
1.6.0-rc.4
...
1.6.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bc6848464 | ||
|
|
abefbfc776 | ||
|
|
ad173ca129 | ||
|
|
d69ef0e39c | ||
|
|
436be17881 | ||
|
|
9a5fa7e699 | ||
|
|
d502ff08c1 | ||
|
|
14eb1281f9 | ||
|
|
8fd7a5aebe | ||
|
|
08423df547 | ||
|
|
40563ed2f8 | ||
|
|
b639f09ca7 | ||
|
|
dd134ad551 | ||
|
|
3d93d50cf0 | ||
|
|
f1da7b6063 | ||
|
|
ef7b33f9b6 | ||
|
|
0f0e6ab1c8 | ||
|
|
5362b312d1 | ||
|
|
ca4d6a398f | ||
|
|
ed00d480f2 | ||
|
|
057bdd546b | ||
|
|
7762f0c85e | ||
|
|
1e6c01ea65 | ||
|
|
4b777f508b | ||
|
|
d15f125964 | ||
|
|
32b435b7e6 | ||
|
|
31d301911f | ||
|
|
911eec5e68 | ||
|
|
2e4bb25e2e | ||
|
|
d99c80eae9 | ||
|
|
0e03240d13 | ||
|
|
02064117bc | ||
|
|
a9e0cc7159 | ||
|
|
6b4332db72 | ||
|
|
0f591953a0 | ||
|
|
0a5e78ccc6 | ||
|
|
fbf7c50a12 | ||
|
|
09c1255239 | ||
|
|
75650ceba3 | ||
|
|
e2a65004f3 | ||
|
|
d4e1bcc660 | ||
|
|
b1b1670c77 | ||
|
|
5a3674f6f6 | ||
|
|
e622e204bf | ||
|
|
c378b06a90 | ||
|
|
c6ce6e6c32 | ||
|
|
355f7ee748 | ||
|
|
c19fa22a26 | ||
|
|
5ba4c8ee5b | ||
|
|
306df5837d | ||
|
|
66bba376db | ||
|
|
ec07d37623 | ||
|
|
cab78d36f3 | ||
|
|
449682baea | ||
|
|
6eb11b9717 | ||
|
|
5a1d138d08 | ||
|
|
dfd75efbe5 | ||
|
|
76ed48fc7c | ||
|
|
1043b9a189 | ||
|
|
e401c683f5 | ||
|
|
9d4fe331fa | ||
|
|
fbae3fd194 | ||
|
|
022f1ce758 | ||
|
|
b367c664c7 | ||
|
|
8512968726 | ||
|
|
2ffc110f03 | ||
|
|
36836c516f | ||
|
|
1f288c25de | ||
|
|
a4b62d48b2 | ||
|
|
397f6902f3 | ||
|
|
e97bceed56 | ||
|
|
7efc0f418e | ||
|
|
ac2a4e1c06 | ||
|
|
ef43348020 | ||
|
|
b6e68bb362 | ||
|
|
8d9ceb5d99 | ||
|
|
af47825b76 | ||
|
|
a4c88697af | ||
|
|
45fbfb098a | ||
|
|
9172e442f2 | ||
|
|
3b91f9af8c | ||
|
|
d5e9cc4bfe | ||
|
|
bb719c5d53 | ||
|
|
05a6775b08 | ||
|
|
1accbb8edc | ||
|
|
a04a7f5714 | ||
|
|
f31f7f7499 | ||
|
|
354d6f307c | ||
|
|
90aa4083ca | ||
|
|
5fbd252db9 | ||
|
|
04d3237a89 | ||
|
|
55aaaeed47 | ||
|
|
84d995335e | ||
|
|
f7d3299ebb | ||
|
|
e762c3add9 | ||
|
|
df6bb065d3 | ||
|
|
2fed02affa | ||
|
|
a739ed6825 | ||
|
|
90c708db2b | ||
|
|
fcbd819f48 |
@@ -2,6 +2,7 @@ language: php
|
||||
php:
|
||||
- '7.1'
|
||||
- '7.2'
|
||||
- '7.3'
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
|
||||
330
CHANGELOG.md
330
CHANGELOG.md
@@ -1,105 +1,62 @@
|
||||
# v1.6.0-rc.4
|
||||
## 03/20/2019
|
||||
# v1.6.4
|
||||
## 04/15/2019
|
||||
|
||||
1. [](#new)
|
||||
* Added new `onPageContent()` event for every call to `Page::content()`
|
||||
* Added phpstan: PHP Static Analysis Tool [#2393](https://github.com/getgrav/grav/pull/2393)
|
||||
* Added `composer test-plugins` to test plugin issues with the current version of Grav
|
||||
* Grav 1.6: Renamed `$grav['users']` service to `$grav['accounts']`
|
||||
* Added `Flex::getObjects()` and `Flex::getMixedCollection()` methods for co-mingled collections
|
||||
* Added support to use single Flex key parameter in `Flex::getObject()` method
|
||||
* Added `FlexObjectInterface::search()` and `FlexCollectionInterface::search()` methods
|
||||
* Override `system.media.upload_limit` with PHP's `post_max_size` or `upload_max_filesize`
|
||||
* Class `Grav\Common\Page\Medium\AbstractMedia` now use array traits instead of extending `Grav\Common\Getters`
|
||||
1. [](#improved)
|
||||
* Renamed `Grav\Framework\File\Formatter\FormatterInterface` to `Grav\Framework\File\Interfaces\FileFormatterInterface`
|
||||
* Improved `File::save()` to use a temporary file if file isn't locked
|
||||
* Improved `|t` filter to better support admin `|tu` style filter if in admin
|
||||
* Update all classes to rely on `PageInterface` instead of `Page` class
|
||||
* Better error checking in `bin/plugin` for existence and enabled
|
||||
* Removed `media.upload_limit` references
|
||||
* Twig `nicenumber`: do not use 0 + string casting hack
|
||||
* Converted Twig tags to use namespaced Twig classes
|
||||
* Site shows error on page rather than hard-crash when page has invalid frontmatter [#2343](https://github.com/getgrav/grav/issues/2343)
|
||||
* Grav 1.6: Greatly improved Flex interfaces
|
||||
1. [](#bugfix)
|
||||
* Grav 1.6: Fixed `FlexUser` loosing ACL information
|
||||
* Grav 1.6: Fixed `FlexUser::find()` breaking when nothing is found
|
||||
* Grav 1.6: Fixed `FlexObject::update()` removing fields on save
|
||||
* Fixed `mkdir(...)` race condition
|
||||
* Fixed `Obtaining write lock failed on file...`
|
||||
* Fixed potential undefined property in `onPageNotFound` event handling
|
||||
* Grav 1.6: Fixed settion caching in `FlexIndex`
|
||||
* Fixed some potential issues/bugs found by phpstan
|
||||
* Fixed regression in GPM packages casted to Array (ref, getgrav/grav-plugin-admin@e3fc4ce)
|
||||
* Fixed session_start(): Setting option 'session.name' failed [#2408](https://github.com/getgrav/grav/issues/2408)
|
||||
* Grav 1.6: Fixed file saving when temporary file cannot be created to the current folder / stream
|
||||
* Grav 1.6: Fixed `File::save()` silently ignoring failures with read only streams
|
||||
* Improved `redirect_default_route` logic as well as `Uri::toArray()` to take into account `root_path` and `extension`
|
||||
* Rework logic to pull out excluded files from pipeline more reliably [#2445](https://github.com/getgrav/grav/issues/2445)
|
||||
* Better logic in `Utils::normalizePath` to handle externals properly [#2216](https://github.com/getgrav/grav/issues/2216)
|
||||
* Fixed to force all `Page::taxonomy` to be treated as strings [#2446](https://github.com/getgrav/grav/issues/2446)
|
||||
* Fixed issue with `Grav['user']` not being available [form#332](https://github.com/getgrav/grav-plugin-form/issues/332)
|
||||
* Updated rounding logic for `Utils::parseSize()` [#2394](https://github.com/getgrav/grav/issues/2394)
|
||||
* Fixed Flex simple storage not being properly initialized if used with caching
|
||||
|
||||
# v1.6.0-rc.3
|
||||
## 02/18/2019
|
||||
# v1.6.3
|
||||
## 04/12/2019
|
||||
|
||||
1. [](#new)
|
||||
* Implemented `Grav\Framework\Psr7` classes as `Nyholm/psr7` decorators
|
||||
* Grav 1.6: Renamed `blueprints/user/accounts.yaml` to `blueprints/user/users.yaml`
|
||||
* Grav 1.6: Moved FlexUser index into `user-data://flex/indexes/users.yaml` [#2378](https://github.com/getgrav/grav/issues/2378)
|
||||
* Added a new `cache-clear` scheduled job to go along with `cache-purge`
|
||||
1. [](#improved)
|
||||
* More code cleanup
|
||||
* Grav 1.6: Fixed `FlexUser` caching
|
||||
* Added back missing `page.types` field in system content configuration [admin#1612](https://github.com/getgrav/grav-plugin-admin/issues/1612)
|
||||
* Console commands: add method for invalidating cache
|
||||
* Updated languages
|
||||
* Added `Blueprint::addDynamicHandler()` method to allow custom dynamic handlers, for example `custom-options@: getCustomOptions`
|
||||
1. [](#bugfix)
|
||||
* Fixed validation for select field type with selectize
|
||||
* Fixed validation for boolean toggles
|
||||
* Grav 1.6: Fixed `Flex[class]::getType()` to return the same value in every class
|
||||
* Grav 1.6: Fixed `FlexIndex` keys being lost when `FlexCollection` gets loaded
|
||||
* Grav 1.6: Fixed missing `form_nonce` for JS when using `FlexForm`
|
||||
* Grav 1.6: Fixed slow loading of `FlexUser` objects on `$grav['users']->find()` and `load()` calls
|
||||
* Missed a `CacheCommand` reference in `bin/grav` [#2442](https://github.com/getgrav/grav/issues/2442)
|
||||
* Fixed issue with `Utils::normalizePath` messing with external URLs [#2216](https://github.com/getgrav/grav/issues/2216)
|
||||
* Fix for `vUndefined` versions when upgrading
|
||||
|
||||
# v1.6.0-rc.2
|
||||
## 02/07/2019
|
||||
# v1.6.2
|
||||
## 04/11/2019
|
||||
|
||||
1. [](#new)
|
||||
* New experimental **FlexObjects** powered `Users` for increased performance and capability (**disabled** by default)
|
||||
* New `$grav['users']` service to allow custom user classes implementing `UserInterface`
|
||||
* Grav 1.6: Added index file support for Flex Objects
|
||||
* Added `LogViewer` helper class and CLI command: `bin/grav logviewer`
|
||||
1. [](#improved)
|
||||
* Grav 1.6: Improved error detection for broken Flex Objects
|
||||
* Removed `apc` and `xcache` support, made `apc` alias of `apcu`
|
||||
* Support admin and regular translations via the `|t` twig filter and `t()` twig function
|
||||
* Improved Grav Core installer/updater to run installer script
|
||||
* Updated vendor libraries including Symfony `4.2.3`
|
||||
* Renamed old `User` class to `Grav\Common\User\DataUser\User` with multiple improvements and small fixes
|
||||
* `User` class now acts as a compatibility layer to older versions of Grav
|
||||
* Deprecated `new User()`, `User::load()`, `User::find()` and `User::delete()` in favor of `$grav['users']` service
|
||||
* `Media` constructor has now support to not to initialize the media objects
|
||||
* Cleanly handle session corruption due to changing Flex object types
|
||||
* Grav 1.6: Renamed `FlexAuthorizeInterface::authorize()` to `isAuthorized()`
|
||||
1. [](#bugfix)
|
||||
* Fixed non-namespaced exceptions in scheduler
|
||||
* Fixed trailing slash redirect in multlang environment [#2350](https://github.com/getgrav/grav/issues/2350)
|
||||
* Grav 1.6: Fixed Flex from indexing hidden folders/files as objects
|
||||
* Grav 1.6 regression: `$session->getFlashObject('files-upload')` did not work with Form 3.0
|
||||
* Revert renaming of `ClearCacheCommand` to ensure CLI GPM upgrades go smoothly
|
||||
|
||||
# v1.6.0-rc.1
|
||||
## 01/30/2019
|
||||
# v1.6.1
|
||||
## 04/11/2019
|
||||
|
||||
1. [](#improved)
|
||||
* Improved `$page->forms()` call, added `$page->addForms()`
|
||||
* Grav 1.6: Made `FormFlashFile` more robust against deleted files
|
||||
* Updated languages from crowdin
|
||||
* Grav 1.6: Fixed a bug in `FormFlashFile::moveTo()` not deleting the old file
|
||||
* Grav 1.6: Fixed `FlexMediaTrait::getMedia()` trying to include uploaded but already moved media
|
||||
* Fixed `ImageMedium` constructor warning when file does not exist
|
||||
* Grav 1.6: Fixed bad host header in PSR-7 (if using `php -S localhost:8000 system/router.php`)
|
||||
|
||||
# v1.6.0-beta.8
|
||||
## 01/25/2019
|
||||
* Improved CSS for the bottom filter bar of DebugBar
|
||||
1. [](#bugfix)
|
||||
* Fixed issue with `@import` not being added to top of pipelined css [#2440](https://github.com/getgrav/grav/issues/2440)
|
||||
|
||||
# v1.6.0
|
||||
## 04/11/2019
|
||||
|
||||
1. [](#new)
|
||||
* Set minimum requirements to [PHP 7.1.3](https://getgrav.org/blog/raising-php-requirements-2018)
|
||||
* New `Scheduler` functionality for periodic jobs
|
||||
* New `Backup` functionality with multiple backup profiles and scheduler integration
|
||||
* Refactored `Assets Manager` to be more powerful and flexible
|
||||
* Updated Doctrine Collections to 1.6
|
||||
* Updated Doctrine Cache to 1.8
|
||||
* Updated Symfony Components to 4.2
|
||||
* Added new Cache purge functionality old cache manually via CLI/Admin as well as scheduler integration
|
||||
* Added new `{% throw 404 'Not Found' %}` twig tag (with custom code/message)
|
||||
* Added `Grav\Framework\File` classes for handling YAML, Markdown, JSON, INI and PHP serialized files
|
||||
* Added `Grav\Framework\Collection\AbstractIndexCollection` class
|
||||
* Added `Grav\Framework\Object\ObjectIndex` class
|
||||
* Added `Grav\Framework\Flex` classes
|
||||
* Added support for hiding form fields in blueprints by using dynamic property like `security@: admin.foobar`, `scope@: object` or `scope-ignore@: object` to any field
|
||||
* New experimental **FlexObjects** powered `Users` for increased performance and capability (**disabled** by default)
|
||||
* Added PSR-7 and PSR-15 classes
|
||||
* Added `Grav\Framework\DI\Container` class
|
||||
* Added `Grav\Framework\RequestHandler\RequestHandler` class
|
||||
* Added `Page::httpResponseCode()` and `Page::httpHeaders()` methods
|
||||
* Added `Grav\Framework\Form\Interfaces\FormInterface`
|
||||
* Added `Grav\Framework\Form\Interfaces\FormFactoryInterface`
|
||||
* Added `Grav\Framework\Form\FormTrait`
|
||||
@@ -111,25 +68,8 @@
|
||||
* Added form preview support for `FlexObject`, including a way to render newly uploaded files before saving them
|
||||
* Added `FlexObject::getChanges()` to determine what fields change during an update
|
||||
* Added `arrayDiffMultidimensional`, `arrayIsAssociative`, `arrayCombine` Util functions
|
||||
1. [](#improved)
|
||||
* Grav 1.6: Added method argument `Data::filter($missingValuesAsNull)`, defaulting to `false`
|
||||
* Improved `Grav\Common\User` class; added `$user->update()` method
|
||||
* Added trim support for text input fields `validate: trim: true`
|
||||
1. [](#bugfix)
|
||||
* Grav 1.6: Fixed environment getting port added [#2284](https://github.com/getgrav/grav/issues/2284)
|
||||
* Grav 1.6: Fixed `FlexForm::updateObject()` to update array values when they are empty in the form
|
||||
* Fixed some issues related to Medium objects losing query string attributes
|
||||
* Broke out Medium timestamp so it's not cleared on `reset()`s
|
||||
* Fixed issue with `redirect_trailing_slash` losing query string [#2269](https://github.com/getgrav/grav/issues/2269)
|
||||
* Fixed failed login if user attempts to log in with upper case non-english letters
|
||||
* Removed extra authenticated/authorized fields when saving existing user from a form
|
||||
* Fixed `Grav\Framework\Route::__toString()` returning relative URL, not relative route
|
||||
|
||||
# v1.6.0-beta.7
|
||||
## 12/14/2018
|
||||
|
||||
1. [](#new)
|
||||
* Updated Symfony Components to 4.2
|
||||
* New `$grav['users']` service to allow custom user classes implementing `UserInterface`
|
||||
* Added `LogViewer` helper class and CLI command: `bin/grav logviewer`
|
||||
* Added `select()` and `unselect()` methods to `CollectionInterface` and its base classes
|
||||
* Added `orderBy()` and `limit()` methods to `ObjectCollectionInterface` and its base classes
|
||||
* Added `user-data://` which is a writable stream (`user://data` is not and should be avoided)
|
||||
@@ -140,46 +80,64 @@
|
||||
* Added `Grav\Framework\Filesystem\Filesystem` class with methods to manipulate stream URLs
|
||||
* Added new `$grav['filesystem']` service using an instance of the new `Filesystem` object
|
||||
* Added `{% render object layout: 'default' with { variable: true } %}` for Flex objects and collections
|
||||
* Grav 1.6: Flex: Added support for custom object index classes (API compatibility break)
|
||||
1. [](#improved)
|
||||
* Improved `Grav\Framework\File\Formatter` classes to have abstract parent class and some useful methods
|
||||
* Grav 1.6: Improved Flex storage classes
|
||||
* Grav 1.6: Improved `Grav\Framework\File` classes to use better type hints and the new `Filesystem` class
|
||||
1. [](#bugfix)
|
||||
* Fixed handling of `append_url_extension` inside of `Page::templateFormat()` [#2264](https://github.com/getgrav/grav/issues/2264)
|
||||
* Fixed a broken language string [#2261](https://github.com/getgrav/grav/issues/2261)
|
||||
* Fixed clearing cache having no effect on Doctrine cache
|
||||
* Fixed `Medium::relativePath()` for streams
|
||||
* Fixed `Object` serialization breaking if overriding `jsonSerialize()` method
|
||||
* Grav 1.6: Fixed `FlexObject::update()` call with partial object update
|
||||
* Fixed `YamlFormatter::decode()` when calling `init_set()` with integer
|
||||
* Fixed session throwing error in CLI if initialized
|
||||
|
||||
# v1.6.0-beta.6
|
||||
## 11/12/2018
|
||||
|
||||
1. [](#new)
|
||||
* Added `$grav->setup()` to simplify CLI and custom access points
|
||||
* Grav 1.6: Added `CsvFormatter` and `CsvFile` classes
|
||||
* Added `CsvFormatter` and `CsvFile` classes
|
||||
* Added new system config option to `pages.hide_empty_folders` if a folder has no valid `.md` file available. Default behavior is `false` for compatibility.
|
||||
* Added new system config option for `languages.pages_fallback_only` forcing only 'fallback' to find page content through supported languages, default behavior is to display any language found if active language is missing
|
||||
* Added `Utils::arrayFlattenDotNotation()` and `Utils::arrayUnflattenDotNotation()` helper methods
|
||||
1. [](#improved)
|
||||
* Add the page to onMarkdownInitialized event [#2412](https://github.com/getgrav/grav/issues/2412)
|
||||
* Doctrine filecache is now namespaced with prefix to support purging
|
||||
* Register all page types into `blueprint://pages` stream
|
||||
* Removed `apc` and `xcache` support, made `apc` alias of `apcu`
|
||||
* Support admin and regular translations via the `|t` twig filter and `t()` twig function
|
||||
* Improved Grav Core installer/updater to run installer script
|
||||
* Updated vendor libraries including Symfony `4.2.3`
|
||||
* Renamed old `User` class to `Grav\Common\User\DataUser\User` with multiple improvements and small fixes
|
||||
* `User` class now acts as a compatibility layer to older versions of Grav
|
||||
* Deprecated `new User()`, `User::load()`, `User::find()` and `User::delete()` in favor of `$grav['users']` service
|
||||
* `Media` constructor has now support to not to initialize the media objects
|
||||
* Cleanly handle session corruption due to changing Flex object types
|
||||
* Added `FlexObjectInterface::getDefaultValue()` and `FormInterface::getDefaultValue()`
|
||||
* Added new `onPageContent()` event for every call to `Page::content()`
|
||||
* Added phpstan: PHP Static Analysis Tool [#2393](https://github.com/getgrav/grav/pull/2393)
|
||||
* Added `composer test-plugins` to test plugin issues with the current version of Grav
|
||||
* Added `Flex::getObjects()` and `Flex::getMixedCollection()` methods for co-mingled collections
|
||||
* Added support to use single Flex key parameter in `Flex::getObject()` method
|
||||
* Added `FlexObjectInterface::search()` and `FlexCollectionInterface::search()` methods
|
||||
* Override `system.media.upload_limit` with PHP's `post_max_size` or `upload_max_filesize`
|
||||
* Class `Grav\Common\Page\Medium\AbstractMedia` now use array traits instead of extending `Grav\Common\Getters`
|
||||
* Implemented `Grav\Framework\Psr7` classes as `Nyholm/psr7` decorators
|
||||
* Added a new `cache-clear` scheduled job to go along with `cache-purge`
|
||||
* Renamed `Grav\Framework\File\Formatter\FormatterInterface` to `Grav\Framework\File\Interfaces\FileFormatterInterface`
|
||||
* Improved `File::save()` to use a temporary file if file isn't locked
|
||||
* Improved `|t` filter to better support admin `|tu` style filter if in admin
|
||||
* Update all classes to rely on `PageInterface` instead of `Page` class
|
||||
* Better error checking in `bin/plugin` for existence and enabled
|
||||
* Removed `media.upload_limit` references
|
||||
* Twig `nicenumber`: do not use 0 + string casting hack
|
||||
* Converted Twig tags to use namespaced Twig classes
|
||||
* Site shows error on page rather than hard-crash when page has invalid frontmatter [#2343](https://github.com/getgrav/grav/issues/2343)
|
||||
* Added `languages.default_lang` option to override the default lang (usually first supported language)
|
||||
* Added `Content-Type: application/json` body support for PSR-7 `ServerRequest`
|
||||
* Remove PHP time limit in `ZipArchive`
|
||||
* DebugBar: Resolve twig templates in deprecated backtraces in order to help locating Twig issues
|
||||
* Added `$grav['cache']->getSimpleCache()` method for getting PSR-16 compatible cache
|
||||
* MediaTrait: Use PSR-16 cache
|
||||
* Improved `Utils::normalizePath()` to support non-protocol URLs
|
||||
* Added ability to reset `Page::metadata` to allow rebuilding from automatically generated values
|
||||
* Added back missing `page.types` field in system content configuration [admin#1612](https://github.com/getgrav/grav-plugin-admin/issues/1612)
|
||||
* Console commands: add method for invalidating cache
|
||||
* Updated languages
|
||||
* Improved `$page->forms()` call, added `$page->addForms()`
|
||||
* Updated languages from crowdin
|
||||
* Fixed `ImageMedium` constructor warning when file does not exist
|
||||
* Improved `Grav\Common\User` class; added `$user->update()` method
|
||||
* Added trim support for text input fields `validate: trim: true`
|
||||
* Improved `Grav\Framework\File\Formatter` classes to have abstract parent class and some useful methods
|
||||
* Support negotiated content types set via the Request `Accept:` header
|
||||
* Support negotiated language types set via the Request `Accept-Language:` header
|
||||
* Cleaned up and sorted the Service `idMap`
|
||||
* Grav 1.6: Allow custom Flex form views
|
||||
1. [](#bugfix)
|
||||
* Fixed `Uri::hasStandardPort()` to support reverse proxy configurations [#1786](https://github.com/getgrav/grav/issues/1786)
|
||||
* Use `append_url_extension` from page header to set template format if set [#2604](https://github.com/getgrav/grav/pull/2064)
|
||||
* Fixed some bugs in Grav environment selection logic
|
||||
|
||||
# v1.6.0-beta.5
|
||||
## 11/05/2018
|
||||
|
||||
1. [](#new)
|
||||
* Added PSR-7 and PSR-15 classes
|
||||
* Added `Grav\Framework\DI\Container` class
|
||||
* Added `Grav\Framework\RequestHandler\RequestHandler` class
|
||||
* Added `Page::httpResponseCode()` and `Page::httpHeaders()` methods
|
||||
1. [](#improved)
|
||||
* Updated `Grav` container object to implement PSR-11 `ContainerInterface`
|
||||
* Updated Grav `Processor` classes to implement PSR-15 `MiddlewareInterface`
|
||||
* Make `Data` class to extend `JsonSerializable`
|
||||
@@ -188,67 +146,55 @@
|
||||
* Set session name based on `security.salt` rather than `GRAV_ROOT` [#2242](https://github.com/getgrav/grav/issues/2242)
|
||||
* Added option to configure list of `xss_invalid_protocols` in `Security` config [#2250](https://github.com/getgrav/grav/issues/2250)
|
||||
* Smarter `security.salt` checking now we use `security.yaml` for other options
|
||||
* Grav 1.6: Merged Grav 1.5.4 fixes in
|
||||
|
||||
# v1.6.0-beta.4
|
||||
## 10/24/2018
|
||||
|
||||
1. [](#new)
|
||||
* Added new system config option to `pages.hide_empty_folders` if a folder has no valid `.md` file available. Default behavior is `false` for compatibility.
|
||||
* Added new system config option for `languages.pages_fallback_only` forcing only 'fallback' to find page content through supported languages, default behavior is to display any language found if active language is missing
|
||||
* Added `Utils::arrayFlattenDotNotation()` and `Utils::arrayUnflattenDotNotation()` helper methods
|
||||
1. [](#improved)
|
||||
* Added apcu autoloader optimization
|
||||
* Additional helper methods in `Language`, `Languages`, and `LanguageCodes` classes
|
||||
1. [](#bugfix)
|
||||
* Use login provider User avatar if set
|
||||
* Fixed `Folder::doDelete($folder, false)` removing symlink when it should not
|
||||
|
||||
# v1.6.0-beta.3
|
||||
## 10/15/2018
|
||||
|
||||
1. [](#improved)
|
||||
* Call `onFatalException` event also on internal PHP errors
|
||||
* Built-in PHP Webserver: log requests before handling them
|
||||
1. [](#bugfix)
|
||||
* Grav 1.6: Scheduler Fallback for never runs and Windows support [#2202](https://github.com/getgrav/grav/pull/2202)
|
||||
|
||||
# v1.6.0-beta.2
|
||||
## 10/09/2018
|
||||
|
||||
1. [](#new)
|
||||
* Grav 1.6: Added Flex support for custom media tasks
|
||||
1. [](#improved)
|
||||
* Built-in PHP Webserver: log requests before handling them
|
||||
* Added support for syslog and syslog facility logging (default: 'file')
|
||||
* Improved usability of `System` configuration blueprint with side-tabs
|
||||
1. [](#bugfix)
|
||||
1. [](#bugfix)
|
||||
* Fixed issue with `Truncator::truncateWords` and `Truncator::truncateLetters` when string not wrapped in tags [#2432](https://github.com/getgrav/grav/issues/2432)
|
||||
* Fixed `Undefined method closure::fields()` when getting avatar for user, thanks @Romarain [#2422](https://github.com/getgrav/grav/issues/2422)
|
||||
* Fixed cached images not being updated when source image is modified
|
||||
* Fixed deleting last list item in the form
|
||||
* Fixed issue with `Utils::url()` method would append extra `base_url` if URL already included it
|
||||
* Fixed `mkdir(...)` race condition
|
||||
* Fixed `Obtaining write lock failed on file...`
|
||||
* Fixed potential undefined property in `onPageNotFound` event handling
|
||||
* Fixed some potential issues/bugs found by phpstan
|
||||
* Fixed regression in GPM packages casted to Array (ref, getgrav/grav-plugin-admin@e3fc4ce)
|
||||
* Fixed session_start(): Setting option 'session.name' failed [#2408](https://github.com/getgrav/grav/issues/2408)
|
||||
* Fixed validation for select field type with selectize
|
||||
* Fixed validation for boolean toggles
|
||||
* Fixed non-namespaced exceptions in scheduler
|
||||
* Fixed trailing slash redirect in multlang environment [#2350](https://github.com/getgrav/grav/issues/2350)
|
||||
* Fixed some issues related to Medium objects losing query string attributes
|
||||
* Broke out Medium timestamp so it's not cleared on `reset()`s
|
||||
* Fixed issue with `redirect_trailing_slash` losing query string [#2269](https://github.com/getgrav/grav/issues/2269)
|
||||
* Fixed failed login if user attempts to log in with upper case non-english letters
|
||||
* Removed extra authenticated/authorized fields when saving existing user from a form
|
||||
* Fixed `Grav\Framework\Route::__toString()` returning relative URL, not relative route
|
||||
* Fixed handling of `append_url_extension` inside of `Page::templateFormat()` [#2264](https://github.com/getgrav/grav/issues/2264)
|
||||
* Fixed a broken language string [#2261](https://github.com/getgrav/grav/issues/2261)
|
||||
* Fixed clearing cache having no effect on Doctrine cache
|
||||
* Fixed `Medium::relativePath()` for streams
|
||||
* Fixed `Object` serialization breaking if overriding `jsonSerialize()` method
|
||||
* Fixed `YamlFormatter::decode()` when calling `init_set()` with integer
|
||||
* Fixed session throwing error in CLI if initialized
|
||||
* Fixed `Uri::hasStandardPort()` to support reverse proxy configurations [#1786](https://github.com/getgrav/grav/issues/1786)
|
||||
* Use `append_url_extension` from page header to set template format if set [#2604](https://github.com/getgrav/grav/pull/2064)
|
||||
* Fixed some bugs in Grav environment selection logic
|
||||
* Use login provider User avatar if set
|
||||
* Fixed `Folder::doDelete($folder, false)` removing symlink when it should not
|
||||
* Fixed asset manager to not add empty assets when they don't exist in the filesystem
|
||||
* Update `script` and `style` Twig tags to use the new `Assets` classes
|
||||
* Fixed asset pipeline to rewrite remote URLs as well as local [#2216](https://github.com/getgrav/grav/issues/2216)
|
||||
* Grav 1.6 regression: Fixed asset manager methods with default legacy attributes
|
||||
|
||||
# v1.6.0-beta.1
|
||||
## 10/01/2018
|
||||
# v1.5.10
|
||||
## 03/21/2019
|
||||
|
||||
1. [](#new)
|
||||
* Set minimum requirements to [PHP 7.1.3](https://getgrav.org/blog/raising-php-requirements-2018)
|
||||
* New `Scheduler` functionality for periodic jobs
|
||||
* New `Backup` functionality with multiple backup profiles and scheduler integration
|
||||
* Refactored `Assets Manager` to be more powerful and flexible
|
||||
* Updated Doctrine Collections to 1.5
|
||||
* Updated Doctrine Cache to 1.8
|
||||
* Updated Symfony Components to 4.1
|
||||
* Added a new Deferred Twig extension to allow adding content to Twig blocks after render
|
||||
* Added new Cache purge functionality old cache manually via CLI/Admin as well as scheduler integration
|
||||
* Added new `{% throw 404 'Not Found' %}` twig tag (with custom code/message)
|
||||
* Added `Grav\Framework\File` classes for handling YAML, Markdown, JSON, INI and PHP serialized files
|
||||
* Added `Grav\Framework\Collection\AbstractIndexCollection` class
|
||||
* Added `Grav\Framework\Object\ObjectIndex` class
|
||||
* Added `Grav\Framework\Flex` classes
|
||||
* Added support for hiding form fields in blueprints by using dynamic property like `security@: admin.foobar`, `scope@: object` or `scope-ignore@: object` to any field
|
||||
1. [](#improved)
|
||||
* Doctrine filecache is now namespaced with prefix to support purging
|
||||
* Register all page types into `blueprint://pages` stream
|
||||
* Added new `deferred` Twig extension
|
||||
|
||||
# v1.5.9
|
||||
## 03/20/2019
|
||||
|
||||
@@ -106,6 +106,7 @@ If you discover a possible security issue related to Grav or one of its plugins,
|
||||
* 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)]
|
||||
|
||||
2
bin/grav
2
bin/grav
@@ -40,7 +40,7 @@ $app->addCommands(array(
|
||||
new \Grav\Console\Cli\ComposerCommand(),
|
||||
new \Grav\Console\Cli\SandboxCommand(),
|
||||
new \Grav\Console\Cli\CleanCommand(),
|
||||
new \Grav\Console\Cli\CacheCommand(),
|
||||
new \Grav\Console\Cli\ClearCacheCommand(),
|
||||
new \Grav\Console\Cli\BackupCommand(),
|
||||
new \Grav\Console\Cli\NewProjectCommand(),
|
||||
new \Grav\Console\Cli\SchedulerCommand(),
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"ext-openssl": "*",
|
||||
"ext-curl": "*",
|
||||
"ext-zip": "*",
|
||||
"ext-dom": "*",
|
||||
"symfony/polyfill-iconv": "^1.9",
|
||||
"symfony/polyfill-php72": "^1.9",
|
||||
"symfony/polyfill-php73": "^1.9",
|
||||
|
||||
410
composer.lock
generated
410
composer.lock
generated
@@ -183,34 +183,36 @@
|
||||
},
|
||||
{
|
||||
"name": "doctrine/collections",
|
||||
"version": "v1.5.0",
|
||||
"version": "v1.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/collections.git",
|
||||
"reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf"
|
||||
"reference": "d2ae4ef05e25197343b6a39bae1d3c427a2f6956"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/collections/zipball/a01ee38fcd999f34d9bfbcee59dbda5105449cbf",
|
||||
"reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf",
|
||||
"url": "https://api.github.com/repos/doctrine/collections/zipball/d2ae4ef05e25197343b6a39bae1d3c427a2f6956",
|
||||
"reference": "d2ae4ef05e25197343b6a39bae1d3c427a2f6956",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1"
|
||||
"php": "^7.1.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "~0.1@dev",
|
||||
"phpunit/phpunit": "^5.7"
|
||||
"doctrine/coding-standard": "^6.0",
|
||||
"phpstan/phpstan-shim": "^0.9.2",
|
||||
"phpunit/phpunit": "^7.0",
|
||||
"vimeo/psalm": "^3.2.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.3.x-dev"
|
||||
"dev-master": "1.6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Doctrine\\Common\\Collections\\": "lib/"
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@@ -239,14 +241,15 @@
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Collections Abstraction library",
|
||||
"homepage": "http://www.doctrine-project.org",
|
||||
"description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.",
|
||||
"homepage": "https://www.doctrine-project.org/projects/collections.html",
|
||||
"keywords": [
|
||||
"array",
|
||||
"collections",
|
||||
"iterator"
|
||||
"iterators",
|
||||
"php"
|
||||
],
|
||||
"time": "2017-07-22T10:37:32+00:00"
|
||||
"time": "2019-03-25T19:03:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "donatj/phpuseragentparser",
|
||||
@@ -1771,16 +1774,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v4.2.4",
|
||||
"version": "v4.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "9dc2299a016497f9ee620be94524e6c0af0280a9"
|
||||
"reference": "24206aff3efe6962593297e57ef697ebb220e384"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/9dc2299a016497f9ee620be94524e6c0af0280a9",
|
||||
"reference": "9dc2299a016497f9ee620be94524e6c0af0280a9",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/24206aff3efe6962593297e57ef697ebb220e384",
|
||||
"reference": "24206aff3efe6962593297e57ef697ebb220e384",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1839,7 +1842,7 @@
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-02-23T15:17:42+00:00"
|
||||
"time": "2019-04-01T07:32:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/contracts",
|
||||
@@ -1911,16 +1914,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v4.2.4",
|
||||
"version": "v4.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "3354d2e6af986dd71f68b4e5cf4a933ab58697fb"
|
||||
"reference": "ca5af306fbc37f3cf597e91bc9cfa0c7d3f33544"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/3354d2e6af986dd71f68b4e5cf4a933ab58697fb",
|
||||
"reference": "3354d2e6af986dd71f68b4e5cf4a933ab58697fb",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ca5af306fbc37f3cf597e91bc9cfa0c7d3f33544",
|
||||
"reference": "ca5af306fbc37f3cf597e91bc9cfa0c7d3f33544",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1971,20 +1974,20 @@
|
||||
],
|
||||
"description": "Symfony EventDispatcher Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-02-23T15:17:42+00:00"
|
||||
"time": "2019-03-30T15:58:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.10.0",
|
||||
"version": "v1.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "e3d826245268269cd66f8326bd8bc066687b4a19"
|
||||
"reference": "82ebae02209c21113908c229e9883c419720738a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19",
|
||||
"reference": "e3d826245268269cd66f8326bd8bc066687b4a19",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a",
|
||||
"reference": "82ebae02209c21113908c229e9883c419720738a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1996,7 +1999,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
"dev-master": "1.11-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2029,20 +2032,20 @@
|
||||
"polyfill",
|
||||
"portable"
|
||||
],
|
||||
"time": "2018-08-06T14:22:27+00:00"
|
||||
"time": "2019-02-06T07:57:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-iconv",
|
||||
"version": "v1.10.0",
|
||||
"version": "v1.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-iconv.git",
|
||||
"reference": "97001cfc283484c9691769f51cdf25259037eba2"
|
||||
"reference": "f037ea22acfaee983e271dd9c3b8bb4150bd8ad7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/97001cfc283484c9691769f51cdf25259037eba2",
|
||||
"reference": "97001cfc283484c9691769f51cdf25259037eba2",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/f037ea22acfaee983e271dd9c3b8bb4150bd8ad7",
|
||||
"reference": "f037ea22acfaee983e271dd9c3b8bb4150bd8ad7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2054,7 +2057,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
"dev-master": "1.11-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2088,20 +2091,20 @@
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2018-09-21T06:26:08+00:00"
|
||||
"time": "2019-02-06T07:57:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.10.0",
|
||||
"version": "v1.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494"
|
||||
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494",
|
||||
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609",
|
||||
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2113,7 +2116,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
"dev-master": "1.11-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2147,20 +2150,20 @@
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2018-09-21T13:07:52+00:00"
|
||||
"time": "2019-02-06T07:57:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php72",
|
||||
"version": "v1.10.0",
|
||||
"version": "v1.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php72.git",
|
||||
"reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631"
|
||||
"reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9050816e2ca34a8e916c3a0ae8b9c2fccf68b631",
|
||||
"reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/ab50dcf166d5f577978419edd37aa2bb8eabce0c",
|
||||
"reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2169,7 +2172,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
"dev-master": "1.11-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2202,20 +2205,20 @@
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2018-09-21T13:07:52+00:00"
|
||||
"time": "2019-02-06T07:57:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php73",
|
||||
"version": "v1.10.0",
|
||||
"version": "v1.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php73.git",
|
||||
"reference": "47ad352296d61aae366f075b8609f4dcc28853ef"
|
||||
"reference": "d1fb4abcc0c47be136208ad9d68bf59f1ee17abd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/47ad352296d61aae366f075b8609f4dcc28853ef",
|
||||
"reference": "47ad352296d61aae366f075b8609f4dcc28853ef",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/d1fb4abcc0c47be136208ad9d68bf59f1ee17abd",
|
||||
"reference": "d1fb4abcc0c47be136208ad9d68bf59f1ee17abd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2224,7 +2227,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
"dev-master": "1.11-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2233,6 +2236,9 @@
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@@ -2257,20 +2263,20 @@
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2018-09-25T06:33:47+00:00"
|
||||
"time": "2019-02-06T07:57:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v4.2.4",
|
||||
"version": "v4.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "6c05edb11fbeff9e2b324b4270ecb17911a8b7ad"
|
||||
"reference": "1e6cbb41dadcaf29e0db034d6ad0d039a9df06e6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/6c05edb11fbeff9e2b324b4270ecb17911a8b7ad",
|
||||
"reference": "6c05edb11fbeff9e2b324b4270ecb17911a8b7ad",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/1e6cbb41dadcaf29e0db034d6ad0d039a9df06e6",
|
||||
"reference": "1e6cbb41dadcaf29e0db034d6ad0d039a9df06e6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2306,11 +2312,11 @@
|
||||
],
|
||||
"description": "Symfony Process Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-01-24T22:05:03+00:00"
|
||||
"time": "2019-03-10T20:07:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-dumper",
|
||||
"version": "v4.2.4",
|
||||
"version": "v4.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/var-dumper.git",
|
||||
@@ -2386,16 +2392,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v4.2.4",
|
||||
"version": "v4.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "761fa560a937fd7686e5274ff89dcfa87a5047df"
|
||||
"reference": "6712daf03ee25b53abb14e7e8e0ede1a770efdb1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/761fa560a937fd7686e5274ff89dcfa87a5047df",
|
||||
"reference": "761fa560a937fd7686e5274ff89dcfa87a5047df",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/6712daf03ee25b53abb14e7e8e0ede1a770efdb1",
|
||||
"reference": "6712daf03ee25b53abb14e7e8e0ede1a770efdb1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2441,20 +2447,20 @@
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-02-23T15:17:42+00:00"
|
||||
"time": "2019-03-30T15:58:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v1.38.2",
|
||||
"version": "v1.38.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "874adbd9222f928f6998732b25b01b41dff15b0c"
|
||||
"reference": "7732e9e7017d751313811bd118de61302e9c8b35"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/874adbd9222f928f6998732b25b01b41dff15b0c",
|
||||
"reference": "874adbd9222f928f6998732b25b01b41dff15b0c",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/7732e9e7017d751313811bd118de61302e9c8b35",
|
||||
"reference": "7732e9e7017d751313811bd118de61302e9c8b35",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2507,7 +2513,7 @@
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2019-03-12T18:45:24+00:00"
|
||||
"time": "2019-03-23T14:27:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "willdurand/negotiation",
|
||||
@@ -2624,16 +2630,16 @@
|
||||
},
|
||||
{
|
||||
"name": "codeception/codeception",
|
||||
"version": "2.5.4",
|
||||
"version": "2.5.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Codeception/Codeception.git",
|
||||
"reference": "a2ecfe2f3ad36cc29904d2d566b0d7280854e6c9"
|
||||
"reference": "547a64cb31edcf1902b296c511f5ca74101bcb4c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/a2ecfe2f3ad36cc29904d2d566b0d7280854e6c9",
|
||||
"reference": "a2ecfe2f3ad36cc29904d2d566b0d7280854e6c9",
|
||||
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/547a64cb31edcf1902b296c511f5ca74101bcb4c",
|
||||
"reference": "547a64cb31edcf1902b296c511f5ca74101bcb4c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2712,7 +2718,7 @@
|
||||
"functional testing",
|
||||
"unit testing"
|
||||
],
|
||||
"time": "2019-02-20T20:45:25+00:00"
|
||||
"time": "2019-03-23T17:57:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "codeception/phpunit-wrapper",
|
||||
@@ -2833,27 +2839,29 @@
|
||||
},
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/instantiator.git",
|
||||
"reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda"
|
||||
"reference": "a2c590166b2133a4633738648b6b064edae0814a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
|
||||
"reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a",
|
||||
"reference": "a2c590166b2133a4633738648b6b064edae0814a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"athletic/athletic": "~0.1.8",
|
||||
"doctrine/coding-standard": "^6.0",
|
||||
"ext-pdo": "*",
|
||||
"ext-phar": "*",
|
||||
"phpunit/phpunit": "^6.2.3",
|
||||
"squizlabs/php_codesniffer": "^3.0.2"
|
||||
"phpbench/phpbench": "^0.13",
|
||||
"phpstan/phpstan-phpunit": "^0.11",
|
||||
"phpstan/phpstan-shim": "^0.11",
|
||||
"phpunit/phpunit": "^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@@ -2878,12 +2886,12 @@
|
||||
}
|
||||
],
|
||||
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
|
||||
"homepage": "https://github.com/doctrine/instantiator",
|
||||
"homepage": "https://www.doctrine-project.org/projects/instantiator.html",
|
||||
"keywords": [
|
||||
"constructor",
|
||||
"instantiate"
|
||||
],
|
||||
"time": "2017-07-22T11:58:36+00:00"
|
||||
"time": "2019-03-17T17:37:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "facebook/webdriver",
|
||||
@@ -3212,39 +3220,36 @@
|
||||
},
|
||||
{
|
||||
"name": "nette/bootstrap",
|
||||
"version": "v2.4.6",
|
||||
"version": "v3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/bootstrap.git",
|
||||
"reference": "268816e3f1bb7426c3a4ceec2bd38a036b532543"
|
||||
"reference": "e1075af05c211915e03e0c86542f3ba5433df4a3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/bootstrap/zipball/268816e3f1bb7426c3a4ceec2bd38a036b532543",
|
||||
"reference": "268816e3f1bb7426c3a4ceec2bd38a036b532543",
|
||||
"url": "https://api.github.com/repos/nette/bootstrap/zipball/e1075af05c211915e03e0c86542f3ba5433df4a3",
|
||||
"reference": "e1075af05c211915e03e0c86542f3ba5433df4a3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nette/di": "~2.4.7",
|
||||
"nette/utils": "~2.4",
|
||||
"php": ">=5.6.0"
|
||||
},
|
||||
"conflict": {
|
||||
"nette/nette": "<2.2"
|
||||
"nette/di": "^3.0",
|
||||
"nette/utils": "^3.0",
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"latte/latte": "~2.2",
|
||||
"nette/application": "~2.3",
|
||||
"nette/caching": "~2.3",
|
||||
"nette/database": "~2.3",
|
||||
"nette/forms": "~2.3",
|
||||
"nette/http": "~2.4.0",
|
||||
"nette/mail": "~2.3",
|
||||
"nette/robot-loader": "^2.4.2 || ^3.0",
|
||||
"nette/safe-stream": "~2.2",
|
||||
"nette/security": "~2.3",
|
||||
"nette/tester": "~2.0",
|
||||
"tracy/tracy": "^2.4.1"
|
||||
"latte/latte": "^2.2",
|
||||
"nette/application": "^3.0",
|
||||
"nette/caching": "^3.0",
|
||||
"nette/database": "^3.0",
|
||||
"nette/forms": "^3.0",
|
||||
"nette/http": "^3.0",
|
||||
"nette/mail": "^3.0",
|
||||
"nette/robot-loader": "^3.0",
|
||||
"nette/safe-stream": "^2.2",
|
||||
"nette/security": "^3.0",
|
||||
"nette/tester": "^2.0",
|
||||
"tracy/tracy": "^2.6"
|
||||
},
|
||||
"suggest": {
|
||||
"nette/robot-loader": "to use Configurator::createRobotLoader()",
|
||||
@@ -3253,7 +3258,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4-dev"
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -3284,46 +3289,50 @@
|
||||
"configurator",
|
||||
"nette"
|
||||
],
|
||||
"time": "2018-05-17T12:52:20+00:00"
|
||||
"time": "2019-03-26T12:59:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nette/di",
|
||||
"version": "v2.4.15",
|
||||
"version": "v3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/di.git",
|
||||
"reference": "d0561b8f77e8ef2ed6d83328860e16c81a5a8649"
|
||||
"reference": "19d83539245aaacb59470828919182411061841f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/di/zipball/d0561b8f77e8ef2ed6d83328860e16c81a5a8649",
|
||||
"reference": "d0561b8f77e8ef2ed6d83328860e16c81a5a8649",
|
||||
"url": "https://api.github.com/repos/nette/di/zipball/19d83539245aaacb59470828919182411061841f",
|
||||
"reference": "19d83539245aaacb59470828919182411061841f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-tokenizer": "*",
|
||||
"nette/neon": "^2.3.3 || ~3.0.0",
|
||||
"nette/php-generator": "^2.6.1 || ^3.0.0",
|
||||
"nette/utils": "^2.5.0 || ~3.0.0",
|
||||
"php": ">=5.6.0"
|
||||
"nette/neon": "^3.0",
|
||||
"nette/php-generator": "^3.2.2",
|
||||
"nette/robot-loader": "^3.2",
|
||||
"nette/schema": "^1.0",
|
||||
"nette/utils": "^3.0",
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"conflict": {
|
||||
"nette/bootstrap": "<2.4",
|
||||
"nette/nette": "<2.2"
|
||||
"nette/bootstrap": "<3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nette/tester": "^2.0",
|
||||
"nette/tester": "^2.2",
|
||||
"tracy/tracy": "^2.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4-dev"
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
],
|
||||
"files": [
|
||||
"src/compatibility.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@@ -3353,7 +3362,7 @@
|
||||
"nette",
|
||||
"static"
|
||||
],
|
||||
"time": "2019-01-30T13:26:05+00:00"
|
||||
"time": "2019-04-03T19:35:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nette/finder",
|
||||
@@ -3407,7 +3416,7 @@
|
||||
"homepage": "https://nette.org/contributors"
|
||||
}
|
||||
],
|
||||
"description": "🔍 Nette Finder: find files and directories with an intuitive API.",
|
||||
"description": "? Nette Finder: find files and directories with an intuitive API.",
|
||||
"homepage": "https://nette.org",
|
||||
"keywords": [
|
||||
"filesystem",
|
||||
@@ -3467,7 +3476,7 @@
|
||||
"homepage": "https://nette.org/contributors"
|
||||
}
|
||||
],
|
||||
"description": "🍸 Nette NEON: encodes and decodes NEON file format.",
|
||||
"description": "? Nette NEON: encodes and decodes NEON file format.",
|
||||
"homepage": "http://ne-on.org",
|
||||
"keywords": [
|
||||
"export",
|
||||
@@ -3480,25 +3489,22 @@
|
||||
},
|
||||
{
|
||||
"name": "nette/php-generator",
|
||||
"version": "v3.2.1",
|
||||
"version": "v3.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/php-generator.git",
|
||||
"reference": "9de4e093a130f7a1bd175198799ebc0efbac6924"
|
||||
"reference": "acff8b136fad84b860a626d133e791f95781f9f5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/php-generator/zipball/9de4e093a130f7a1bd175198799ebc0efbac6924",
|
||||
"reference": "9de4e093a130f7a1bd175198799ebc0efbac6924",
|
||||
"url": "https://api.github.com/repos/nette/php-generator/zipball/acff8b136fad84b860a626d133e791f95781f9f5",
|
||||
"reference": "acff8b136fad84b860a626d133e791f95781f9f5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nette/utils": "^2.4.2 || ~3.0.0",
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"conflict": {
|
||||
"nette/nette": "<2.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"nette/tester": "^2.0",
|
||||
"tracy/tracy": "^2.3"
|
||||
@@ -3538,30 +3544,27 @@
|
||||
"php",
|
||||
"scaffolding"
|
||||
],
|
||||
"time": "2018-11-27T19:00:14+00:00"
|
||||
"time": "2019-03-15T03:41:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nette/robot-loader",
|
||||
"version": "v3.1.1",
|
||||
"version": "v3.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/robot-loader.git",
|
||||
"reference": "3e8d75d6d976e191bdf46752ca40a286671219d2"
|
||||
"reference": "0712a0e39ae7956d6a94c0ab6ad41aa842544b5c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/robot-loader/zipball/3e8d75d6d976e191bdf46752ca40a286671219d2",
|
||||
"reference": "3e8d75d6d976e191bdf46752ca40a286671219d2",
|
||||
"url": "https://api.github.com/repos/nette/robot-loader/zipball/0712a0e39ae7956d6a94c0ab6ad41aa842544b5c",
|
||||
"reference": "0712a0e39ae7956d6a94c0ab6ad41aa842544b5c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-tokenizer": "*",
|
||||
"nette/finder": "^2.3 || ^3.0",
|
||||
"nette/utils": "^2.4 || ^3.0",
|
||||
"php": ">=5.6.0"
|
||||
},
|
||||
"conflict": {
|
||||
"nette/nette": "<2.2"
|
||||
"nette/finder": "^2.5",
|
||||
"nette/utils": "^3.0",
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"nette/tester": "^2.0",
|
||||
@@ -3570,7 +3573,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.1-dev"
|
||||
"dev-master": "3.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -3594,7 +3597,7 @@
|
||||
"homepage": "https://nette.org/contributors"
|
||||
}
|
||||
],
|
||||
"description": "🍀 Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.",
|
||||
"description": "? Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.",
|
||||
"homepage": "https://nette.org",
|
||||
"keywords": [
|
||||
"autoload",
|
||||
@@ -3603,27 +3606,81 @@
|
||||
"nette",
|
||||
"trait"
|
||||
],
|
||||
"time": "2019-03-01T20:23:02+00:00"
|
||||
"time": "2019-03-08T21:57:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nette/utils",
|
||||
"version": "v2.5.3",
|
||||
"name": "nette/schema",
|
||||
"version": "v1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/utils.git",
|
||||
"reference": "17b9f76f2abd0c943adfb556e56f2165460b15ce"
|
||||
"url": "https://github.com/nette/schema.git",
|
||||
"reference": "6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/17b9f76f2abd0c943adfb556e56f2165460b15ce",
|
||||
"reference": "17b9f76f2abd0c943adfb556e56f2165460b15ce",
|
||||
"url": "https://api.github.com/repos/nette/schema/zipball/6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d",
|
||||
"reference": "6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.6.0"
|
||||
"nette/utils": "^3.0.1",
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"conflict": {
|
||||
"nette/nette": "<2.2"
|
||||
"require-dev": {
|
||||
"nette/tester": "^2.2",
|
||||
"tracy/tracy": "^2.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause",
|
||||
"GPL-2.0",
|
||||
"GPL-3.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "David Grudl",
|
||||
"homepage": "https://davidgrudl.com"
|
||||
},
|
||||
{
|
||||
"name": "Nette Community",
|
||||
"homepage": "https://nette.org/contributors"
|
||||
}
|
||||
],
|
||||
"description": "📐 Nette Schema: validating data structures against a given Schema.",
|
||||
"homepage": "https://nette.org",
|
||||
"keywords": [
|
||||
"config",
|
||||
"nette"
|
||||
],
|
||||
"time": "2019-04-03T15:53:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nette/utils",
|
||||
"version": "v3.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/utils.git",
|
||||
"reference": "bd961f49b211997202bda1d0fbc410905be370d4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/bd961f49b211997202bda1d0fbc410905be370d4",
|
||||
"reference": "bd961f49b211997202bda1d0fbc410905be370d4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"nette/tester": "~2.0",
|
||||
@@ -3632,7 +3689,7 @@
|
||||
"suggest": {
|
||||
"ext-gd": "to use Image",
|
||||
"ext-iconv": "to use Strings::webalize() and toAscii()",
|
||||
"ext-intl": "for script transliteration in Strings::webalize() and toAscii()",
|
||||
"ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
|
||||
"ext-json": "to use Nette\\Utils\\Json",
|
||||
"ext-mbstring": "to use Strings::lower() etc...",
|
||||
"ext-xml": "to use Strings::length() etc. when mbstring is not available"
|
||||
@@ -3640,15 +3697,12 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.5-dev"
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
],
|
||||
"files": [
|
||||
"src/loader.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@@ -3685,7 +3739,7 @@
|
||||
"utility",
|
||||
"validation"
|
||||
],
|
||||
"time": "2018-09-18T10:22:16+00:00"
|
||||
"time": "2019-03-22T01:00:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
@@ -4153,16 +4207,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "0.11.4",
|
||||
"version": "0.11.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "ccc4f854748664cc61d1f3d4ecb26810df1f0cd4"
|
||||
"reference": "24ce5a566a798b81343138ed5d41d6877554cf9a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/ccc4f854748664cc61d1f3d4ecb26810df1f0cd4",
|
||||
"reference": "ccc4f854748664cc61d1f3d4ecb26810df1f0cd4",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/24ce5a566a798b81343138ed5d41d6877554cf9a",
|
||||
"reference": "24ce5a566a798b81343138ed5d41d6877554cf9a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4222,7 +4276,7 @@
|
||||
"MIT"
|
||||
],
|
||||
"description": "PHPStan - PHP Static Analysis Tool",
|
||||
"time": "2019-03-14T14:46:15+00:00"
|
||||
"time": "2019-03-25T16:40:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-deprecation-rules",
|
||||
@@ -4524,16 +4578,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "7.5.7",
|
||||
"version": "7.5.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "eb343b86753d26de07ecba7868fa983104361948"
|
||||
"reference": "c29c0525cf4572c11efe1db49a8b8aee9dfac58a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/eb343b86753d26de07ecba7868fa983104361948",
|
||||
"reference": "eb343b86753d26de07ecba7868fa983104361948",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c29c0525cf4572c11efe1db49a8b8aee9dfac58a",
|
||||
"reference": "c29c0525cf4572c11efe1db49a8b8aee9dfac58a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4604,7 +4658,7 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2019-03-16T07:31:17+00:00"
|
||||
"time": "2019-03-26T13:23:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit-reverse-lookup",
|
||||
@@ -5174,7 +5228,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/browser-kit",
|
||||
"version": "v4.2.4",
|
||||
"version": "v4.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/browser-kit.git",
|
||||
@@ -5231,7 +5285,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
"version": "v4.2.4",
|
||||
"version": "v4.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/css-selector.git",
|
||||
@@ -5284,7 +5338,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/dom-crawler",
|
||||
"version": "v4.2.4",
|
||||
"version": "v4.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dom-crawler.git",
|
||||
@@ -5341,7 +5395,7 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v4.2.4",
|
||||
"version": "v4.2.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
@@ -5390,16 +5444,16 @@
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/theseer/tokenizer.git",
|
||||
"reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b"
|
||||
"reference": "1c42705be2b6c1de5904f8afacef5895cab44bf8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b",
|
||||
"reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/1c42705be2b6c1de5904f8afacef5895cab44bf8",
|
||||
"reference": "1c42705be2b6c1de5904f8afacef5895cab44bf8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5426,7 +5480,7 @@
|
||||
}
|
||||
],
|
||||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||
"time": "2017-04-07T12:08:54+00:00"
|
||||
"time": "2019-04-04T09:56:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "victorjonsson/markdowndocs",
|
||||
|
||||
@@ -30,9 +30,25 @@ div.phpdebugbar {
|
||||
}
|
||||
|
||||
.phpdebugbar .phpdebugbar-widgets-toolbar {
|
||||
border-top: 1px solid #ddd;
|
||||
padding-left: 5px;
|
||||
padding-right: 2px;
|
||||
padding-top: 2px;
|
||||
background-color: #fafafa !important;
|
||||
width: auto !important;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.phpdebugbar .phpdebugbar-widgets-toolbar input {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.phpdebugbar .phpdebugbar-widgets-toolbar .phpdebugbar-widgets-filter {
|
||||
|
||||
}
|
||||
|
||||
|
||||
.phpdebugbar input[type=text] {
|
||||
padding: 0;
|
||||
display: inline;
|
||||
|
||||
@@ -323,6 +323,12 @@ form:
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
languages.default_lang:
|
||||
type: text
|
||||
size: x-small
|
||||
label: PLUGIN_ADMIN.DEFAULT_LANG
|
||||
help: PLUGIN_ADMIN.DEFAULT_LANG_HELP
|
||||
|
||||
languages.include_default_lang:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.INCLUDE_DEFAULT_LANG
|
||||
|
||||
@@ -13,6 +13,7 @@ intl_enabled: true # Special logic for PHP Interna
|
||||
|
||||
languages:
|
||||
supported: [] # List of languages supported. eg: [en, fr, de]
|
||||
default_lang: # Default is the first supported language. Must be one of the supported languages
|
||||
include_default_lang: true # Include the default lang prefix in all URLs
|
||||
pages_fallback_only: false # Only fallback to find page content through supported languages
|
||||
translations: true # Enable translations by default
|
||||
@@ -53,7 +54,7 @@ pages:
|
||||
special_chars: # List of special characters to automatically convert to entities
|
||||
'>': 'gt'
|
||||
'<': 'lt'
|
||||
types: [html,htm,json,xml,txt,rss,atom] # list of valid page types
|
||||
types: [html,htm,xml,txt,json,rss,atom] # list of valid page types
|
||||
append_url_extension: '' # Append page's extension in Page urls (e.g. '.html' results in /path/page.html)
|
||||
expires: 604800 # Page expires time in seconds (604800 seconds = 7 days)
|
||||
cache_control: # Can be blank for no setting, or a valid `cache-control` text value
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
// Some standard defines
|
||||
define('GRAV', true);
|
||||
define('GRAV_VERSION', '1.6.0-rc.4');
|
||||
define('GRAV_TESTING', true);
|
||||
define('GRAV_VERSION', '1.6.4');
|
||||
define('GRAV_TESTING', false);
|
||||
define('DS', '/');
|
||||
|
||||
if (!defined('GRAV_PHP_MIN')) {
|
||||
|
||||
@@ -37,12 +37,6 @@ class Assets extends PropertyObject
|
||||
/** @const Regex to match JavaScript files */
|
||||
const JS_REGEX = '/.\.js$/i';
|
||||
|
||||
/**
|
||||
* @const Regex to match <script> or <style> tag when adding inline style/script. Note that this only supports a
|
||||
* single tag, so the check is greedy to avoid issues in JS.
|
||||
*/
|
||||
const HTML_TAG_REGEX = '#(<([A-Z][A-Z0-9]*)>)+(.*)(<\/\2>)#is';
|
||||
|
||||
protected $assets_dir;
|
||||
protected $assets_url;
|
||||
|
||||
@@ -51,8 +45,10 @@ class Assets extends PropertyObject
|
||||
|
||||
// Config Options
|
||||
protected $css_pipeline;
|
||||
protected $css_pipeline_include_externals;
|
||||
protected $css_pipeline_before_excludes;
|
||||
protected $js_pipeline;
|
||||
protected $js_pipeline_include_externals;
|
||||
protected $js_pipeline_before_excludes;
|
||||
protected $pipeline_options = [];
|
||||
|
||||
@@ -270,6 +266,21 @@ class Assets extends PropertyObject
|
||||
protected function filterAssets($assets, $key, $value, $sort = false)
|
||||
{
|
||||
$results = array_filter($assets, function($asset) use ($key, $value) {
|
||||
|
||||
if ($key === 'position' && $value === 'pipeline') {
|
||||
|
||||
$type = $asset->getType();
|
||||
|
||||
if ($asset->getRemote() && $this->{$type . '_pipeline_include_externals'} === false) {
|
||||
if ($this->{$type . '_pipeline_before_excludes'}) {
|
||||
$asset->setPosition('after');
|
||||
} else {
|
||||
$asset->setPosition('before');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
if ($asset[$key] === $value) return true;
|
||||
return false;
|
||||
});
|
||||
@@ -298,11 +309,9 @@ class Assets extends PropertyObject
|
||||
$before_output = '';
|
||||
$pipeline_output = '';
|
||||
$after_output = '';
|
||||
$no_pipeline = [];
|
||||
|
||||
$assets = 'assets_' . $type;
|
||||
$pipeline_enabled = $type . '_pipeline';
|
||||
$before_excludes = $type . '_pipeline_before_excludes';
|
||||
$render_pipeline = 'render' . ucfirst($type);
|
||||
|
||||
$group_assets = $this->filterAssets($this->$assets, 'group', $group);
|
||||
@@ -315,22 +324,13 @@ class Assets extends PropertyObject
|
||||
$options = array_merge($this->pipeline_options, ['timestamp' => $this->timestamp]);
|
||||
|
||||
$pipeline = new Pipeline($options);
|
||||
$pipeline_output = $pipeline->$render_pipeline($pipeline_assets, $group, $attributes, $no_pipeline);
|
||||
$pipeline_output = $pipeline->$render_pipeline($pipeline_assets, $group, $attributes);
|
||||
} else {
|
||||
foreach ($pipeline_assets as $asset) {
|
||||
$pipeline_output .= $asset->render();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle stuff that couldn't be pipelined
|
||||
if (!empty($no_pipeline)) {
|
||||
if ($this->{$before_excludes}) {
|
||||
$after_assets = array_merge($after_assets, $no_pipeline);
|
||||
} else {
|
||||
$before_assets = array_merge($before_assets, $no_pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
// Before Pipeline
|
||||
foreach ($before_assets as $asset) {
|
||||
$before_output .= $asset->render();
|
||||
|
||||
@@ -129,6 +129,12 @@ abstract class BaseAsset extends PropertyObject
|
||||
return $this->remote;
|
||||
}
|
||||
|
||||
public function setPosition($position)
|
||||
{
|
||||
$this->position = $position;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -33,6 +33,8 @@ class Pipeline extends PropertyObject
|
||||
/** @const Regex to match CSS import content */
|
||||
protected const CSS_IMPORT_REGEX = '{@import(.*?);}';
|
||||
|
||||
protected const FIRST_FORWARDSLASH_REGEX = '{^\/{1}\w}';
|
||||
|
||||
protected $css_minify;
|
||||
protected $css_minify_windows;
|
||||
protected $css_rewrite;
|
||||
@@ -48,9 +50,6 @@ class Pipeline extends PropertyObject
|
||||
protected $query;
|
||||
protected $asset;
|
||||
|
||||
protected $css_pipeline_include_externals;
|
||||
protected $js_pipeline_include_externals;
|
||||
|
||||
/**
|
||||
* Closure used by the pipeline to fetch assets.
|
||||
*
|
||||
@@ -89,11 +88,10 @@ class Pipeline extends PropertyObject
|
||||
* @param array $assets
|
||||
* @param string $group
|
||||
* @param array $attributes
|
||||
* @param array $no_pipeline
|
||||
*
|
||||
* @return bool|string URL or generated content if available, else false
|
||||
*/
|
||||
public function renderCss($assets, $group, $attributes = [], &$no_pipeline = [])
|
||||
public function renderCss($assets, $group, $attributes = [])
|
||||
{
|
||||
// temporary list of assets to pipeline
|
||||
$inline_group = false;
|
||||
@@ -117,21 +115,13 @@ class Pipeline extends PropertyObject
|
||||
if (file_exists($this->assets_dir . $file)) {
|
||||
$buffer = file_get_contents($this->assets_dir . $file) . "\n";
|
||||
} else {
|
||||
|
||||
foreach ($assets as $id => $asset) {
|
||||
if ($this->css_pipeline_include_externals === false && $asset->getRemote()) {
|
||||
$no_pipeline[$id] = $asset;
|
||||
unset($assets[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
//if nothing found get out of here!
|
||||
if (empty($assets) && empty($no_pipeline)) {
|
||||
if (empty($assets)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Concatenate files
|
||||
$buffer = $this->gatherLinks($assets, self::CSS_ASSET, $no_pipeline);
|
||||
$buffer = $this->gatherLinks($assets, self::CSS_ASSET);
|
||||
|
||||
// Minify if required
|
||||
if ($this->shouldMinify('css')) {
|
||||
@@ -162,11 +152,10 @@ class Pipeline extends PropertyObject
|
||||
* @param array $assets
|
||||
* @param string $group
|
||||
* @param array $attributes
|
||||
* @param array $no_pipeline
|
||||
*
|
||||
* @return bool|string URL or generated content if available, else false
|
||||
*/
|
||||
public function renderJs($assets, $group, $attributes = [], &$no_pipeline = [])
|
||||
public function renderJs($assets, $group, $attributes = [])
|
||||
{
|
||||
// temporary list of assets to pipeline
|
||||
$inline_group = false;
|
||||
@@ -190,21 +179,13 @@ class Pipeline extends PropertyObject
|
||||
if (file_exists($this->assets_dir . $file)) {
|
||||
$buffer = file_get_contents($this->assets_dir . $file) . "\n";
|
||||
} else {
|
||||
|
||||
foreach ($assets as $id => $asset) {
|
||||
if ($this->js_pipeline_include_externals === false && $asset->getRemote()) {
|
||||
$no_pipeline[$id] = $asset;
|
||||
unset($assets[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
//if nothing found get out of here!
|
||||
if (empty($assets) && empty($no_pipeline)) {
|
||||
if (empty($assets)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Concatenate files
|
||||
$buffer = $this->gatherLinks($assets, self::JS_ASSET, $no_pipeline);
|
||||
$buffer = $this->gatherLinks($assets, self::JS_ASSET);
|
||||
|
||||
// Minify if required
|
||||
if ($this->shouldMinify('js')) {
|
||||
@@ -251,13 +232,21 @@ class Pipeline extends PropertyObject
|
||||
$old_url = $matches[2];
|
||||
|
||||
// Ensure link is not rooted to web server, a data URL, or to a remote host
|
||||
if (Utils::startsWith($old_url, '/') || Utils::startsWith($old_url, 'data:') || $this->isRemoteLink($old_url)) {
|
||||
if (preg_match(self::FIRST_FORWARDSLASH_REGEX, $old_url) || Utils::startsWith($old_url, 'data:') || $this->isRemoteLink($old_url)) {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
$new_url = ($local ? $this->base_url: '') . ltrim(Utils::normalizePath($dir . '/' . $old_url), '/');
|
||||
// clean leading /
|
||||
$old_url = Utils::normalizePath($dir . '/' . $old_url);
|
||||
if (preg_match(self::FIRST_FORWARDSLASH_REGEX, $old_url)) {
|
||||
$old_url = ltrim($old_url, '/');
|
||||
}
|
||||
|
||||
return str_replace($old_url, $new_url, $matches[0]);
|
||||
$new_url = ($local ? $this->base_url: '') . $old_url;
|
||||
|
||||
$fixed = str_replace($matches[2], $new_url, $matches[0]);
|
||||
|
||||
return $fixed;
|
||||
}, $file);
|
||||
|
||||
return $file;
|
||||
|
||||
@@ -38,11 +38,10 @@ trait AssetUtilsTrait
|
||||
*
|
||||
* @param array $assets
|
||||
* @param bool $css
|
||||
* @param array $no_pipeline
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function gatherLinks(array $assets, $css = true, &$no_pipeline = [])
|
||||
protected function gatherLinks(array $assets, $css = true)
|
||||
{
|
||||
$buffer = '';
|
||||
|
||||
@@ -74,9 +73,6 @@ trait AssetUtilsTrait
|
||||
|
||||
// No file found, skip it...
|
||||
if ($file === false) {
|
||||
if (!$local) { // Assume we couldn't download this file for some reason assume it's not pipeline compatible
|
||||
$no_pipeline[$id] = $asset;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -113,7 +109,7 @@ trait AssetUtilsTrait
|
||||
{
|
||||
$imports = [];
|
||||
|
||||
$file = (string)preg_replace_callback(self::CSS_IMPORT_REGEX, function ($matches) {
|
||||
$file = (string)preg_replace_callback(self::CSS_IMPORT_REGEX, function ($matches) use (&$imports) {
|
||||
$imports[] = $matches[0];
|
||||
|
||||
return '';
|
||||
|
||||
@@ -13,6 +13,7 @@ use \Doctrine\Common\Cache as DoctrineCache;
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Common\Scheduler\Scheduler;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
use RocketTheme\Toolbox\Event\EventDispatcher;
|
||||
|
||||
@@ -44,6 +45,11 @@ class Cache extends Getters
|
||||
*/
|
||||
protected $driver;
|
||||
|
||||
/**
|
||||
* @var CacheInterface
|
||||
*/
|
||||
protected $simpleCache;
|
||||
|
||||
protected $driver_name;
|
||||
|
||||
protected $driver_setting;
|
||||
@@ -140,6 +146,23 @@ class Cache extends Getters
|
||||
$dispatcher->addListener('onSchedulerInitialized', [$this, 'onSchedulerInitialized']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CacheInterface
|
||||
*/
|
||||
public function getSimpleCache()
|
||||
{
|
||||
if (null === $this->simpleCache) {
|
||||
$cache = new \Grav\Framework\Cache\Adapter\DoctrineCache($this->driver, '', $this->getLifetime());
|
||||
|
||||
// Disable cache key validation.
|
||||
$cache->setValidation(false);
|
||||
|
||||
$this->simpleCache = $cache;
|
||||
}
|
||||
|
||||
return $this->simpleCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the old out of date file-based caches
|
||||
*
|
||||
|
||||
@@ -25,6 +25,18 @@ class Blueprint extends BlueprintForm
|
||||
/** @var BlueprintSchema */
|
||||
protected $blueprintSchema;
|
||||
|
||||
/** @var array */
|
||||
protected $defaults;
|
||||
|
||||
protected $handlers = [];
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
if ($this->blueprintSchema) {
|
||||
$this->blueprintSchema = clone $this->blueprintSchema;
|
||||
}
|
||||
}
|
||||
|
||||
public function setScope($scope)
|
||||
{
|
||||
$this->scope = $scope;
|
||||
@@ -56,7 +68,60 @@ class Blueprint extends BlueprintForm
|
||||
{
|
||||
$this->initInternals();
|
||||
|
||||
return $this->blueprintSchema->getDefaults();
|
||||
if (null === $this->defaults) {
|
||||
$this->defaults = $this->blueprintSchema->getDefaults();
|
||||
}
|
||||
|
||||
return $this->defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize blueprints with its dynamic fields.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
foreach ($this->dynamic as $key => $data) {
|
||||
// Locate field.
|
||||
$path = explode('/', $key);
|
||||
$current = &$this->items;
|
||||
|
||||
foreach ($path as $field) {
|
||||
if (\is_object($current)) {
|
||||
// Handle objects.
|
||||
if (!isset($current->{$field})) {
|
||||
$current->{$field} = [];
|
||||
}
|
||||
|
||||
$current = &$current->{$field};
|
||||
} else {
|
||||
// Handle arrays and scalars.
|
||||
if (!\is_array($current)) {
|
||||
$current = [$field => []];
|
||||
} elseif (!isset($current[$field])) {
|
||||
$current[$field] = [];
|
||||
}
|
||||
|
||||
$current = &$current[$field];
|
||||
}
|
||||
}
|
||||
|
||||
// Set dynamic property.
|
||||
foreach ($data as $property => $call) {
|
||||
$action = $call['action'];
|
||||
$method = 'dynamic' . ucfirst($action);
|
||||
|
||||
if (isset($this->handlers[$action])) {
|
||||
$callable = $this->handlers[$action];
|
||||
$callable($current, $property, $call);
|
||||
} elseif (method_exists($this, $method)) {
|
||||
$this->{$method}($current, $property, $call);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,6 +223,11 @@ class Blueprint extends BlueprintForm
|
||||
return $this->blueprintSchema;
|
||||
}
|
||||
|
||||
public function addDynamicHandler(string $name, callable $callable): void
|
||||
{
|
||||
$this->handlers[$name] = $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize validator.
|
||||
*/
|
||||
@@ -174,6 +244,7 @@ class Blueprint extends BlueprintForm
|
||||
|
||||
$this->blueprintSchema->embed('', $this->items);
|
||||
$this->blueprintSchema->init();
|
||||
$this->defaults = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -216,12 +216,12 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array|null $data
|
||||
* @param array $toggles
|
||||
* @param array $nested
|
||||
* @return array
|
||||
* @return array|null
|
||||
*/
|
||||
protected function processFormRecursive(array $data, array $toggles, array $nested)
|
||||
protected function processFormRecursive(?array $data, array $toggles, array $nested)
|
||||
{
|
||||
foreach ($nested as $key => $value) {
|
||||
if ($key === '') {
|
||||
@@ -233,11 +233,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
|
||||
}
|
||||
if (is_array($value)) {
|
||||
// Recursively fetch the items.
|
||||
$array = $this->processFormRecursive($data[$key] ?? [], $toggles[$key] ?? [], $value);
|
||||
|
||||
if (!empty($array)) {
|
||||
$data[$key] = $array;
|
||||
}
|
||||
$data[$key] = $this->processFormRecursive($data[$key] ?? null, $toggles[$key] ?? [], $value);
|
||||
} else {
|
||||
$field = $this->get($value);
|
||||
// Do not add the field if:
|
||||
|
||||
@@ -21,6 +21,9 @@ use DebugBar\DebugBar;
|
||||
use DebugBar\JavascriptRenderer;
|
||||
use DebugBar\StandardDebugBar;
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Processors\ProcessorInterface;
|
||||
use Twig\Template;
|
||||
use Twig\TemplateWrapper;
|
||||
|
||||
class Debugger
|
||||
{
|
||||
@@ -44,7 +47,7 @@ class Debugger
|
||||
/** @var array */
|
||||
protected $timers = [];
|
||||
|
||||
/** @var string[] $deprecations */
|
||||
/** @var array $deprecations */
|
||||
protected $deprecations = [];
|
||||
|
||||
/** @var callable */
|
||||
@@ -356,57 +359,183 @@ class Debugger
|
||||
return true;
|
||||
}
|
||||
|
||||
$backtrace = debug_backtrace(false);
|
||||
// Figure out error scope from the error.
|
||||
$scope = 'unknown';
|
||||
if (stripos($errstr, 'grav') !== false) {
|
||||
$scope = 'grav';
|
||||
} elseif (strpos($errfile, '/twig/') !== false) {
|
||||
$scope = 'twig';
|
||||
} elseif (stripos($errfile, '/yaml/') !== false) {
|
||||
$scope = 'yaml';
|
||||
} elseif (strpos($errfile, '/vendor/') !== false) {
|
||||
$scope = 'vendor';
|
||||
}
|
||||
|
||||
// Clean up backtrace to make it more useful.
|
||||
$backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT);
|
||||
|
||||
// Skip current call.
|
||||
array_shift($backtrace);
|
||||
|
||||
// Find yaml file where the error happened.
|
||||
if ($scope === 'yaml') {
|
||||
foreach ($backtrace as $current) {
|
||||
if (isset($current['args'])) {
|
||||
foreach ($current['args'] as $arg) {
|
||||
if ($arg instanceof \SplFileInfo) {
|
||||
$arg = $arg->getPathname();
|
||||
}
|
||||
if (\is_string($arg) && preg_match('/.+\.(yaml|md)$/i', $arg)) {
|
||||
$errfile = $arg;
|
||||
$errline = 0;
|
||||
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter arguments.
|
||||
$cut = 0;
|
||||
$previous = null;
|
||||
foreach ($backtrace as $i => &$current) {
|
||||
if (isset($current['args'])) {
|
||||
$args = [];
|
||||
foreach ($current['args'] as $arg) {
|
||||
if (\is_string($arg)) {
|
||||
$arg = "'" . $arg . "'";
|
||||
if (mb_strlen($arg) > 100) {
|
||||
$arg = 'string';
|
||||
}
|
||||
} elseif (\is_bool($arg)) {
|
||||
$arg = $arg ? 'true' : 'false';
|
||||
} elseif (\is_scalar($arg)) {
|
||||
$arg = $arg;
|
||||
} elseif (\is_object($arg)) {
|
||||
$arg = get_class($arg) . ' $object';
|
||||
} elseif (\is_array($arg)) {
|
||||
$arg = '$array';
|
||||
} else {
|
||||
$arg = '$object';
|
||||
}
|
||||
|
||||
$args[] = $arg;
|
||||
}
|
||||
$current['args'] = $args;
|
||||
}
|
||||
|
||||
$object = $current['object'] ?? null;
|
||||
unset($current['object']);
|
||||
|
||||
$reflection = null;
|
||||
if ($object instanceof TemplateWrapper) {
|
||||
$reflection = new \ReflectionObject($object);
|
||||
$property = $reflection->getProperty('template');
|
||||
$property->setAccessible(true);
|
||||
$object = $property->getValue($object);
|
||||
}
|
||||
|
||||
if ($object instanceof Template) {
|
||||
$file = $current['file'] ?? null;
|
||||
|
||||
if (preg_match('`(Template.php|TemplateWrapper.php)$`', $file)) {
|
||||
$current = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
$debugInfo = $object->getDebugInfo();
|
||||
|
||||
$line = 1;
|
||||
if (!$reflection) {
|
||||
foreach ($debugInfo as $codeLine => $templateLine) {
|
||||
if ($codeLine <= $current['line']) {
|
||||
$line = $templateLine;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$src = $object->getSourceContext();
|
||||
//$code = preg_split('/\r\n|\r|\n/', $src->getCode());
|
||||
//$current['twig']['twig'] = trim($code[$line - 1]);
|
||||
$current['twig']['file'] = $src->getPath();
|
||||
$current['twig']['line'] = $line;
|
||||
|
||||
$prevFile = $previous['file'] ?? null;
|
||||
if ($prevFile && $file === $prevFile) {
|
||||
$prevLine = $previous['line'];
|
||||
|
||||
$line = 1;
|
||||
foreach ($debugInfo as $codeLine => $templateLine) {
|
||||
if ($codeLine <= $prevLine) {
|
||||
$line = $templateLine;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//$previous['twig']['twig'] = trim($code[$line - 1]);
|
||||
$previous['twig']['file'] = $src->getPath();
|
||||
$previous['twig']['line'] = $line;
|
||||
}
|
||||
|
||||
$cut = $i;
|
||||
} elseif ($object instanceof ProcessorInterface) {
|
||||
$cut = $cut ?: $i;
|
||||
break;
|
||||
}
|
||||
|
||||
$previous = &$backtrace[$i];
|
||||
}
|
||||
unset($current);
|
||||
|
||||
if ($cut) {
|
||||
$backtrace = array_slice($backtrace, 0, $cut + 1);
|
||||
}
|
||||
$backtrace = array_values(array_filter($backtrace));
|
||||
|
||||
// Skip vendor libraries and the method where error was triggered.
|
||||
while ($current = array_shift($backtrace)) {
|
||||
if (isset($current['file']) && strpos($current['file'], 'vendor') !== false) {
|
||||
foreach ($backtrace as $i => $current) {
|
||||
if (!isset($current['file'])) {
|
||||
continue;
|
||||
}
|
||||
if (strpos($current['file'], '/vendor/') !== false) {
|
||||
$cut = $i + 1;
|
||||
continue;
|
||||
}
|
||||
if (isset($current['function']) && ($current['function'] === 'user_error' || $current['function'] === 'trigger_error')) {
|
||||
$current = array_shift($backtrace);
|
||||
$cut = $i + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Add back last call.
|
||||
array_unshift($backtrace, $current);
|
||||
|
||||
// Filter arguments.
|
||||
foreach ($backtrace as &$current) {
|
||||
if (isset($current['args'])) {
|
||||
$args = [];
|
||||
foreach ($current['args'] as $arg) {
|
||||
if (\is_string($arg)) {
|
||||
$args[] = "'" . $arg . "'";
|
||||
} elseif (\is_bool($arg)) {
|
||||
$args[] = $arg ? 'true' : 'false';
|
||||
} elseif (\is_scalar($arg)) {
|
||||
$args[] = $arg;
|
||||
} elseif (\is_object($arg)) {
|
||||
$args[] = get_class($arg) . ' $object';
|
||||
} elseif (\is_array($arg)) {
|
||||
$args[] = '$array';
|
||||
} else {
|
||||
$args[] = '$object';
|
||||
}
|
||||
}
|
||||
$current['args'] = $args;
|
||||
}
|
||||
if ($cut) {
|
||||
$backtrace = array_slice($backtrace, $cut);
|
||||
}
|
||||
unset($current);
|
||||
$backtrace = array_values(array_filter($backtrace));
|
||||
|
||||
$this->deprecations[] = [
|
||||
$current = reset($backtrace);
|
||||
|
||||
// If the issue happened inside twig file, change the file and line to match that file.
|
||||
$file = $current['twig']['file'] ?? '';
|
||||
if ($file) {
|
||||
$errfile = $file;
|
||||
$errline = $current['twig']['line'] ?? 0;
|
||||
}
|
||||
|
||||
$deprecation = [
|
||||
'scope' => $scope,
|
||||
'message' => $errstr,
|
||||
'file' => $errfile,
|
||||
'line' => $errline,
|
||||
'trace' => $backtrace,
|
||||
'count' => 1
|
||||
];
|
||||
|
||||
$this->deprecations[] = $deprecation;
|
||||
|
||||
// Do not pass forward.
|
||||
return true;
|
||||
}
|
||||
@@ -431,38 +560,37 @@ class Debugger
|
||||
|
||||
protected function getDepracatedMessage($deprecated)
|
||||
{
|
||||
$scope = 'unknown';
|
||||
if (stripos($deprecated['message'], 'grav') !== false) {
|
||||
$scope = 'grav';
|
||||
} elseif (!isset($deprecated['file'])) {
|
||||
$scope = 'unknown';
|
||||
} elseif (stripos($deprecated['file'], 'twig') !== false) {
|
||||
$scope = 'twig';
|
||||
} elseif (stripos($deprecated['file'], 'yaml') !== false) {
|
||||
$scope = 'yaml';
|
||||
} elseif (stripos($deprecated['file'], 'vendor') !== false) {
|
||||
$scope = 'vendor';
|
||||
}
|
||||
$scope = $deprecated['scope'];
|
||||
|
||||
$trace = [];
|
||||
foreach ($deprecated['trace'] as $current) {
|
||||
$class = $current['class'] ?? '';
|
||||
$type = $current['type'] ?? '';
|
||||
$function = $this->getFunction($current);
|
||||
if (isset($current['file'])) {
|
||||
$current['file'] = str_replace(GRAV_ROOT . '/', '', $current['file']);
|
||||
if (isset($deprecated['trace'])) {
|
||||
foreach ($deprecated['trace'] as $current) {
|
||||
$class = $current['class'] ?? '';
|
||||
$type = $current['type'] ?? '';
|
||||
$function = $this->getFunction($current);
|
||||
if (isset($current['file'])) {
|
||||
$current['file'] = str_replace(GRAV_ROOT . '/', '', $current['file']);
|
||||
}
|
||||
|
||||
unset($current['class'], $current['type'], $current['function'], $current['args']);
|
||||
|
||||
if (isset($current['twig'])) {
|
||||
$trace[] = $current['twig'];
|
||||
} else {
|
||||
$trace[] = ['call' => $class . $type . $function] + $current;
|
||||
}
|
||||
}
|
||||
|
||||
unset($current['class'], $current['type'], $current['function'], $current['args']);
|
||||
|
||||
$trace[] = ['call' => $class . $type . $function] + $current;
|
||||
}
|
||||
|
||||
$array = [
|
||||
'message' => $deprecated['message'],
|
||||
'file' => $deprecated['file'],
|
||||
'line' => $deprecated['line'],
|
||||
'trace' => $trace
|
||||
];
|
||||
|
||||
return [
|
||||
[
|
||||
'message' => $deprecated['message'],
|
||||
'trace' => $trace
|
||||
],
|
||||
array_filter($array),
|
||||
$scope
|
||||
];
|
||||
}
|
||||
@@ -473,6 +601,6 @@ class Debugger
|
||||
return '';
|
||||
}
|
||||
|
||||
return $trace['function'] . '(' . implode(', ', $trace['args']) . ')';
|
||||
return $trace['function'] . '(' . implode(', ', $trace['args'] ?? []) . ')';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
namespace Grav\Common\Filesystem;
|
||||
|
||||
use Grav\Common\Utils;
|
||||
|
||||
abstract class Archiver
|
||||
{
|
||||
protected $options = [
|
||||
@@ -35,6 +37,11 @@ abstract class Archiver
|
||||
|
||||
public function setOptions($options)
|
||||
{
|
||||
// Set infinite PHP execution time if possible.
|
||||
if (function_exists('set_time_limit') && !Utils::isFunctionDisabled('set_time_limit')) {
|
||||
set_time_limit(0);
|
||||
}
|
||||
|
||||
$this->options = $options + $this->options;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -12,11 +12,16 @@ namespace Grav\Common\GPM\Remote;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\GPM\Common\Package as BasePackage;
|
||||
|
||||
class Package extends BasePackage
|
||||
class Package extends BasePackage implements \JsonSerializable
|
||||
{
|
||||
public function __construct($package, $package_type = null)
|
||||
{
|
||||
$data = new Data($package);
|
||||
parent::__construct($data, $package_type);
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,13 +41,12 @@ class Truncator {
|
||||
return $html;
|
||||
}
|
||||
|
||||
$dom = self::htmlToDomDocument($html);
|
||||
|
||||
// Grab the body of our DOM.
|
||||
$body = $dom->getElementsByTagName('body')->item(0);
|
||||
$doc = self::htmlToDomDocument($html);
|
||||
$container = $doc->getElementsByTagName('div')->item(0);
|
||||
$container = $container->parentNode->removeChild($container);
|
||||
|
||||
// Iterate over words.
|
||||
$words = new DOMWordsIterator($body);
|
||||
$words = new DOMWordsIterator($container);
|
||||
$truncated = false;
|
||||
foreach ($words as $word) {
|
||||
|
||||
@@ -66,7 +65,7 @@ class Truncator {
|
||||
$words[$offset][1] + strlen($words[$offset][0])
|
||||
);
|
||||
|
||||
self::removeProceedingNodes($curNode, $body);
|
||||
self::removeProceedingNodes($curNode, $container);
|
||||
|
||||
if (!empty($ellipsis)) {
|
||||
self::insertEllipsis($curNode, $ellipsis);
|
||||
@@ -81,7 +80,7 @@ class Truncator {
|
||||
|
||||
// Return original HTML if not truncated.
|
||||
if ($truncated) {
|
||||
return self::innerHTML($body);
|
||||
$html = self::getCleanedHtml($doc, $container);
|
||||
}
|
||||
|
||||
return $html;
|
||||
@@ -100,13 +99,12 @@ class Truncator {
|
||||
return $html;
|
||||
}
|
||||
|
||||
$dom = self::htmlToDomDocument($html);
|
||||
|
||||
// Grab the body of our DOM.
|
||||
$body = $dom->getElementsByTagName('body')->item(0);
|
||||
$doc = self::htmlToDomDocument($html);
|
||||
$container = $doc->getElementsByTagName('div')->item(0);
|
||||
$container = $container->parentNode->removeChild($container);
|
||||
|
||||
// Iterate over letters.
|
||||
$letters = new DOMLettersIterator($body);
|
||||
$letters = new DOMLettersIterator($container);
|
||||
$truncated = false;
|
||||
foreach ($letters as $letter) {
|
||||
|
||||
@@ -115,7 +113,7 @@ class Truncator {
|
||||
|
||||
$currentText = $letters->currentTextPosition();
|
||||
$currentText[0]->nodeValue = mb_substr($currentText[0]->nodeValue, 0, $currentText[1] + 1);
|
||||
self::removeProceedingNodes($currentText[0], $body);
|
||||
self::removeProceedingNodes($currentText[0], $container);
|
||||
|
||||
if (!empty($ellipsis)) {
|
||||
self::insertEllipsis($currentText[0], $ellipsis);
|
||||
@@ -129,7 +127,7 @@ class Truncator {
|
||||
|
||||
// Return original HTML if not truncated.
|
||||
if ($truncated) {
|
||||
return self::innerHTML($body);
|
||||
$html = self::getCleanedHtml($doc, $container);
|
||||
}
|
||||
|
||||
return $html;
|
||||
@@ -143,7 +141,7 @@ class Truncator {
|
||||
public static function htmlToDomDocument($html)
|
||||
{
|
||||
if (!$html) {
|
||||
$html = '<p></p>';
|
||||
$html = '';
|
||||
}
|
||||
|
||||
// Transform multibyte entities which otherwise display incorrectly.
|
||||
@@ -155,7 +153,7 @@ class Truncator {
|
||||
// Instantiate new DOMDocument object, and then load in UTF-8 HTML.
|
||||
$dom = new DOMDocument();
|
||||
$dom->encoding = 'UTF-8';
|
||||
$dom->loadHTML($html);
|
||||
$dom->loadHTML("<div>$html</div>");
|
||||
|
||||
return $dom;
|
||||
}
|
||||
@@ -188,6 +186,27 @@ class Truncator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean extra code
|
||||
*
|
||||
* @param DOMDocument $doc
|
||||
* @param $container
|
||||
* @return string
|
||||
*/
|
||||
private static function getCleanedHTML(DOMDocument $doc, $container)
|
||||
{
|
||||
while ($doc->firstChild) {
|
||||
$doc->removeChild($doc->firstChild);
|
||||
}
|
||||
|
||||
while ($container->firstChild ) {
|
||||
$doc->appendChild($container->firstChild);
|
||||
}
|
||||
|
||||
$html = trim($doc->saveHTML());
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an ellipsis
|
||||
* @param DOMNode|DOMElement $domNode Element to insert after.
|
||||
@@ -215,21 +234,102 @@ class Truncator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the innerHTML of a particular DOMElement
|
||||
*
|
||||
* @param DOMElement $element
|
||||
* @return string
|
||||
* @inheritDoc
|
||||
*/
|
||||
private static function innerHTML($element) {
|
||||
$innerHTML = '';
|
||||
$children = $element->childNodes;
|
||||
foreach ($children as $child)
|
||||
{
|
||||
$tmp_dom = new DOMDocument();
|
||||
$tmp_dom->appendChild($tmp_dom->importNode($child, true));
|
||||
$innerHTML.=trim($tmp_dom->saveHTML());
|
||||
public function truncate(
|
||||
$text,
|
||||
$length = 100,
|
||||
$ending = '...',
|
||||
$exact = false,
|
||||
$considerHtml = true
|
||||
) {
|
||||
if ($considerHtml) {
|
||||
// if the plain text is shorter than the maximum length, return the whole text
|
||||
if (strlen(preg_replace('/<.*?>/', '', $text)) <= $length) {
|
||||
return $text;
|
||||
}
|
||||
// splits all html-tags to scanable lines
|
||||
preg_match_all('/(<.+?>)?([^<>]*)/s', $text, $lines, PREG_SET_ORDER);
|
||||
$total_length = strlen($ending);
|
||||
$open_tags = array();
|
||||
$truncate = '';
|
||||
foreach ($lines as $line_matchings) {
|
||||
// if there is any html-tag in this line, handle it and add it (uncounted) to the output
|
||||
if (!empty($line_matchings[1])) {
|
||||
// if it's an "empty element" with or without xhtml-conform closing slash
|
||||
if (preg_match('/^<(\s*.+?\/\s*|\s*(img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param)(\s.+?)?)>$/is', $line_matchings[1])) {
|
||||
// do nothing
|
||||
// if tag is a closing tag
|
||||
} else if (preg_match('/^<\s*\/([^\s]+?)\s*>$/s', $line_matchings[1], $tag_matchings)) {
|
||||
// delete tag from $open_tags list
|
||||
$pos = array_search($tag_matchings[1], $open_tags);
|
||||
if ($pos !== false) {
|
||||
unset($open_tags[$pos]);
|
||||
}
|
||||
// if tag is an opening tag
|
||||
} else if (preg_match('/^<\s*([^\s>!]+).*?>$/s', $line_matchings[1], $tag_matchings)) {
|
||||
// add tag to the beginning of $open_tags list
|
||||
array_unshift($open_tags, strtolower($tag_matchings[1]));
|
||||
}
|
||||
// add html-tag to $truncate'd text
|
||||
$truncate .= $line_matchings[1];
|
||||
}
|
||||
// calculate the length of the plain text part of the line; handle entities as one character
|
||||
$content_length = strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', ' ', $line_matchings[2]));
|
||||
if ($total_length+$content_length> $length) {
|
||||
// the number of characters which are left
|
||||
$left = $length - $total_length;
|
||||
$entities_length = 0;
|
||||
// search for html entities
|
||||
if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', $line_matchings[2], $entities, PREG_OFFSET_CAPTURE)) {
|
||||
// calculate the real length of all entities in the legal range
|
||||
foreach ($entities[0] as $entity) {
|
||||
if ($entity[1]+1-$entities_length <= $left) {
|
||||
$left--;
|
||||
$entities_length += strlen($entity[0]);
|
||||
} else {
|
||||
// no more characters left
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$truncate .= substr($line_matchings[2], 0, $left+$entities_length);
|
||||
// maximum lenght is reached, so get off the loop
|
||||
break;
|
||||
} else {
|
||||
$truncate .= $line_matchings[2];
|
||||
$total_length += $content_length;
|
||||
}
|
||||
// if the maximum length is reached, get off the loop
|
||||
if($total_length>= $length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (strlen($text) <= $length) {
|
||||
return $text;
|
||||
} else {
|
||||
$truncate = substr($text, 0, $length - strlen($ending));
|
||||
}
|
||||
}
|
||||
return $innerHTML;
|
||||
// if the words shouldn't be cut in the middle...
|
||||
if (!$exact) {
|
||||
// ...search the last occurance of a space...
|
||||
$spacepos = strrpos($truncate, ' ');
|
||||
if (isset($spacepos)) {
|
||||
// ...and cut the text in this position
|
||||
$truncate = substr($truncate, 0, $spacepos);
|
||||
}
|
||||
}
|
||||
// add the defined ending to the text
|
||||
$truncate .= $ending;
|
||||
if($considerHtml) {
|
||||
// close all unclosed html-tags
|
||||
foreach ($open_tags as $tag) {
|
||||
$truncate .= '</' . $tag . '>';
|
||||
}
|
||||
}
|
||||
return $truncate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,7 +51,13 @@ class Language
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->default = reset($this->languages);
|
||||
$default = $this->config->get('system.languages.default_lang');
|
||||
if (isset($default) && $this->validate($default)) {
|
||||
$this->default = $default;
|
||||
} else {
|
||||
$this->default = reset($this->languages);
|
||||
}
|
||||
|
||||
$this->page_extensions = null;
|
||||
|
||||
if (empty($this->languages)) {
|
||||
|
||||
@@ -48,7 +48,7 @@ trait ParsedownGravTrait
|
||||
$this->setMarkupEscaped($defaults['escape_markup']);
|
||||
$this->setSpecialChars($defaults['special_chars']);
|
||||
|
||||
$grav->fireEvent('onMarkdownInitialized', new Event(['markdown' => $this]));
|
||||
$grav->fireEvent('onMarkdownInitialized', new Event(['markdown' => $this, 'page' => $page]));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ use Grav\Common\Cache;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Media\Interfaces\MediaCollectionInterface;
|
||||
use Grav\Common\Page\Media;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
trait MediaTrait
|
||||
@@ -71,9 +72,9 @@ trait MediaTrait
|
||||
|
||||
// Use cached media if possible.
|
||||
$cacheKey = md5('media' . $this->getCacheKey());
|
||||
if (!$media = $cache->fetch($cacheKey)) {
|
||||
if (!$media = $cache->get($cacheKey)) {
|
||||
$media = new Media($this->getMediaFolder(), $this->getMediaOrder());
|
||||
$cache->save($cacheKey, $media);
|
||||
$cache->set($cacheKey, $media);
|
||||
}
|
||||
$this->media = $media;
|
||||
}
|
||||
@@ -91,7 +92,7 @@ trait MediaTrait
|
||||
{
|
||||
$cache = $this->getMediaCache();
|
||||
$cacheKey = md5('media' . $this->getCacheKey());
|
||||
$cache->save($cacheKey, $media);
|
||||
$cache->set($cacheKey, $media);
|
||||
|
||||
$this->media = $media;
|
||||
|
||||
@@ -111,11 +112,14 @@ trait MediaTrait
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Cache
|
||||
* @return CacheInterface
|
||||
*/
|
||||
protected function getMediaCache()
|
||||
{
|
||||
return Grav::instance()['cache'];
|
||||
/** @var Cache $cache */
|
||||
$cache = Grav::instance()['cache'];
|
||||
|
||||
return $cache->getSimpleCache();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,13 +33,14 @@ class ImageFile extends Image
|
||||
/**
|
||||
* This is the same as the Gregwar Image class except this one fires a Grav Event on creation of new cached file
|
||||
*
|
||||
* @param string $type the image type
|
||||
* @param int $quality the quality (for JPEG)
|
||||
* @param bool $actual
|
||||
* @param string $type the image type
|
||||
* @param int $quality the quality (for JPEG)
|
||||
* @param bool $actual
|
||||
* @param array $extras
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function cacheFile($type = 'jpg', $quality = 80, $actual = false)
|
||||
public function cacheFile($type = 'jpg', $quality = 80, $actual = false, $extras = [])
|
||||
{
|
||||
if ($type === 'guess') {
|
||||
$type = $this->guessType();
|
||||
@@ -50,7 +51,7 @@ class ImageFile extends Image
|
||||
}
|
||||
|
||||
// Computes the hash
|
||||
$this->hash = $this->getHash($type, $quality);
|
||||
$this->hash = $this->getHash($type, $quality, $extras);
|
||||
|
||||
// Seo friendly image names
|
||||
$seofriendly = Grav::instance()['config']->get('system.images.seofriendly', false);
|
||||
@@ -103,4 +104,42 @@ class ImageFile extends Image
|
||||
|
||||
return $this->getFilename($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hash.
|
||||
* @param string $type
|
||||
* @param int $quality
|
||||
* @param [] $extras
|
||||
* @return null
|
||||
*/
|
||||
public function getHash($type = 'guess', $quality = 80, $extras = [])
|
||||
{
|
||||
if (null === $this->hash) {
|
||||
$this->generateHash($type, $quality, $extras);
|
||||
}
|
||||
|
||||
return $this->hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the hash.
|
||||
* @param string $type
|
||||
* @param int $quality
|
||||
* @param array $extras
|
||||
*/
|
||||
public function generateHash($type = 'guess', $quality = 80, $extras = [])
|
||||
{
|
||||
$inputInfos = $this->source->getInfos();
|
||||
|
||||
$datas = array(
|
||||
$inputInfos,
|
||||
$this->serializeOperations(),
|
||||
$type,
|
||||
$quality,
|
||||
$extras
|
||||
);
|
||||
|
||||
$this->hash = sha1(serialize($datas));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -619,7 +619,7 @@ class ImageMedium extends Medium
|
||||
$this->image->merge(ImageFile::open($overlay));
|
||||
}
|
||||
|
||||
return $this->image->cacheFile($this->format, $this->quality);
|
||||
return $this->image->cacheFile($this->format, $this->quality, false, [$this->get('width'), $this->get('height'), $this->get('modified')]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -414,9 +414,7 @@ class Page implements PageInterface
|
||||
$this->markdown_extra = (bool)$this->header->markdown_extra;
|
||||
}
|
||||
if (isset($this->header->taxonomy)) {
|
||||
foreach ((array)$this->header->taxonomy as $taxonomy => $taxitems) {
|
||||
$this->taxonomy[$taxonomy] = (array)$taxitems;
|
||||
}
|
||||
$this->taxonomy($this->header->taxonomy);
|
||||
}
|
||||
if (isset($this->header->max_count)) {
|
||||
$this->max_count = (int)$this->header->max_count;
|
||||
@@ -1744,6 +1742,14 @@ class Page implements PageInterface
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the metadata and pull from header again
|
||||
*/
|
||||
public function resetMetadata()
|
||||
{
|
||||
$this->metadata = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets and Sets the slug for the Page. The slug is used in the URL routing. If not set it uses
|
||||
* the parent folder from the path
|
||||
@@ -2288,6 +2294,14 @@ class Page implements PageInterface
|
||||
public function taxonomy($var = null)
|
||||
{
|
||||
if ($var !== null) {
|
||||
// make sure first level are arrays
|
||||
array_walk($var, function(&$value) {
|
||||
$value = (array) $value;
|
||||
});
|
||||
// make sure all values are strings
|
||||
array_walk_recursive($var, function(&$value) {
|
||||
$value = (string) $value;
|
||||
});
|
||||
$this->taxonomy = $var;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace Grav\Common\Processors;
|
||||
|
||||
use Grav\Framework\Psr7\Response;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
@@ -25,5 +26,6 @@ class DebuggerAssetsProcessor extends ProcessorBase
|
||||
$this->stopTimer();
|
||||
|
||||
return $handler->handle($request);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,13 @@ class RequestProcessor extends ProcessorBase
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
|
||||
{
|
||||
$this->startTimer();
|
||||
|
||||
$header = $request->getHeaderLine('Content-Type');
|
||||
$type = trim(strstr($header, ';', true) ?: $header);
|
||||
if ($type === 'application/json') {
|
||||
$request = $request->withParsedBody(json_decode($request->getBody()->getContents(), true));
|
||||
}
|
||||
|
||||
$request = $request
|
||||
->withAttribute('grav', $this->container)
|
||||
->withAttribute('time', $_SERVER['REQUEST_TIME_FLOAT'] ?? GRAV_REQUEST_TIME)
|
||||
|
||||
@@ -234,7 +234,7 @@ class Scheduler
|
||||
{
|
||||
$phpBinaryFinder = new PhpExecutableFinder();
|
||||
$php = $phpBinaryFinder->find();
|
||||
$command = 'cd ' . GRAV_ROOT . ';' . $php . ' bin/grav scheduler';
|
||||
$command = 'cd ' . str_replace(' ', '\ ', GRAV_ROOT) . ';' . $php . ' bin/grav scheduler';
|
||||
|
||||
return "(crontab -l; echo \"* * * * * {$command} 1>> /dev/null 2>&1\") | crontab -";
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
namespace Grav\Common\Service;
|
||||
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Debugger;
|
||||
use Grav\Common\User\DataUser;
|
||||
use Grav\Common\User\FlexUser;
|
||||
use Grav\Common\User\User;
|
||||
@@ -26,7 +27,10 @@ class AccountsServiceProvider implements ServiceProviderInterface
|
||||
public function register(Container $container)
|
||||
{
|
||||
$container['accounts'] = function (Container $container) {
|
||||
/** @var Debugger $debugger */
|
||||
$debugger = $container['debugger'];
|
||||
if ($container['config']->get('system.accounts.type') === 'flex') {
|
||||
$debugger->addMessage('User Accounts: Flex Directory');
|
||||
return $this->flexAccounts($container);
|
||||
}
|
||||
|
||||
@@ -100,8 +104,9 @@ class AccountsServiceProvider implements ServiceProviderInterface
|
||||
'formatter' => ['class' => YamlFormatter::class],
|
||||
'folder' => 'account://',
|
||||
'pattern' => '{FOLDER}/{KEY:2}/{KEY}/user.yaml',
|
||||
'key' => 'username',
|
||||
'indexed' => true
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -111,8 +116,9 @@ class AccountsServiceProvider implements ServiceProviderInterface
|
||||
'formatter' => ['class' => YamlFormatter::class],
|
||||
'folder' => 'account://',
|
||||
'pattern' => '{FOLDER}/{KEY}.yaml',
|
||||
'key' => 'storage_key',
|
||||
'indexed' => true
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,8 @@ class PagesServiceProvider implements ServiceProviderInterface
|
||||
}
|
||||
// Default route test and redirect
|
||||
if ($config->get('system.pages.redirect_default_route') && $page->route() !== $path) {
|
||||
$uri->setUriProperties(['path' => $page->route()]);
|
||||
$url = (string) $uri;
|
||||
$c->redirect($url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,11 +187,9 @@ class Uri
|
||||
$this->extension = $parts['extension'];
|
||||
}
|
||||
|
||||
$valid_page_types = implode('|', $config->get('system.pages.types'));
|
||||
|
||||
// Strip the file extension for valid page types
|
||||
if (preg_match('/\.(' . $valid_page_types . ')$/', $parts['basename'])) {
|
||||
$path = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, $parts['dirname']), DS) . '/' . $parts['filename'];
|
||||
if ($this->isValidExtension($this->extension)) {
|
||||
$path = Utils::replaceLastOccurrence(".{$this->extension}", '', $path);
|
||||
}
|
||||
|
||||
// set the new url
|
||||
@@ -586,13 +584,16 @@ class Uri
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
$root_path = $this->root_path ?? '';
|
||||
$extension = isset($this->extension) && $this->isValidExtension($this->extension) ? '.' . $this->extension : '';
|
||||
$path = $root_path . $this->path . $extension;
|
||||
return [
|
||||
'scheme' => $this->scheme,
|
||||
'host' => $this->host,
|
||||
'port' => $this->port,
|
||||
'user' => $this->user,
|
||||
'pass' => $this->password,
|
||||
'path' => $this->path,
|
||||
'path' => $path,
|
||||
'params' => $this->params,
|
||||
'query' => $this->query,
|
||||
'fragment' => $this->fragment
|
||||
@@ -767,7 +768,7 @@ class Uri
|
||||
$normalized_path = Utils::normalizePath($pages_dir . $url_path);
|
||||
} else {
|
||||
$page_route = ($page->home() && !empty($url_path)) ? $page->rawRoute() : $page->route();
|
||||
$normalized_url = $base_url . Utils::normalizePath($page_route . '/' . $url_path);
|
||||
$normalized_url = $base_url . Utils::normalizePath(rtrim($page_route, '/') . '/' . $url_path);
|
||||
$normalized_path = Utils::normalizePath($page->path() . '/' . $url_path);
|
||||
}
|
||||
|
||||
@@ -1326,6 +1327,38 @@ class Uri
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a valid Grav extension
|
||||
*
|
||||
* @param $extension
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidExtension($extension)
|
||||
{
|
||||
$valid_page_types = implode('|', Grav::instance()['config']->get('system.pages.types'));
|
||||
|
||||
// Strip the file extension for valid page types
|
||||
if (preg_match('/(' . $valid_page_types . ')/', $extension)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow overriding of any element (be careful!)
|
||||
*
|
||||
* @param $data
|
||||
* @return Uri
|
||||
*/
|
||||
public function setUriProperties($data)
|
||||
{
|
||||
foreach (get_object_vars($this) as $property => $default) {
|
||||
if (!array_key_exists($property, $data)) continue;
|
||||
$this->{$property} = $data[$property]; // assign value to object
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base URI with port if needed
|
||||
*
|
||||
|
||||
@@ -153,7 +153,7 @@ class User extends Data implements UserInterface
|
||||
|
||||
public function getMediaFolder()
|
||||
{
|
||||
return $this->blueprints->fields()['avatar']['destination'] ?? 'user://accounts/avatars';
|
||||
return $this->blueprints()->fields()['avatar']['destination'] ?? 'user://accounts/avatars';
|
||||
}
|
||||
|
||||
public function getMediaOrder()
|
||||
|
||||
@@ -161,9 +161,9 @@ class User extends FlexObject implements UserInterface, MediaManipulationInterfa
|
||||
* @param string|null $separator
|
||||
* @return mixed
|
||||
*/
|
||||
public function value($name, $default = null, $separator = null)
|
||||
public function getFormValue(string $name, $default = null, string $separator = null)
|
||||
{
|
||||
$value = parent::value($name, null, $separator);
|
||||
$value = parent::getFormValue($name, null, $separator);
|
||||
|
||||
if ($name === 'avatar') {
|
||||
return $this->parseFileProperty($value);
|
||||
@@ -245,6 +245,7 @@ class User extends FlexObject implements UserInterface, MediaManipulationInterfa
|
||||
*/
|
||||
public function join($name, $value, $separator = null)
|
||||
{
|
||||
$separator = $separator ?? '.';
|
||||
$old = $this->get($name, null, $separator);
|
||||
if ($old !== null) {
|
||||
if (!\is_array($old)) {
|
||||
|
||||
@@ -102,8 +102,8 @@ class UserIndex extends FlexIndex
|
||||
|
||||
protected static function updateIndexData(array &$entry, array $data)
|
||||
{
|
||||
$entry['key'] = mb_strtolower($data['username'] ?? $data['email'] ?? $entry['key']);
|
||||
$entry['email'] = mb_strtolower($data['email']) ?? null;
|
||||
$entry['key'] = mb_strtolower($entry['key']);
|
||||
$entry['email'] = isset($data['email']) ? mb_strtolower($data['email']) : null;
|
||||
}
|
||||
|
||||
protected static function getIndexFile(FlexStorageInterface $storage)
|
||||
|
||||
@@ -20,6 +20,10 @@ abstract class Utils
|
||||
{
|
||||
protected static $nonces = [];
|
||||
|
||||
protected const ROOTURL_REGEX = '{^((?:http[s]?:\/\/[^\/]+)|(?:\/\/[^\/]+))(.*)}';
|
||||
|
||||
// ^((?:http[s]?:)?[\/]?(?:\/))
|
||||
|
||||
/**
|
||||
* Simple helper method to make getting a Grav URL easier
|
||||
*
|
||||
@@ -30,7 +34,7 @@ abstract class Utils
|
||||
public static function url($input, $domain = false)
|
||||
{
|
||||
if (!trim((string)$input)) {
|
||||
return false;
|
||||
$input = '/';
|
||||
}
|
||||
|
||||
if (Grav::instance()['config']->get('system.absolute_urls', false)) {
|
||||
@@ -41,6 +45,12 @@ abstract class Utils
|
||||
return $input;
|
||||
}
|
||||
|
||||
/** @var Uri $uri */
|
||||
$uri = Grav::instance()['uri'];
|
||||
|
||||
$root = $uri->rootUrl();
|
||||
$input = Utils::replaceFirstOccurrence($root, '', $input);
|
||||
|
||||
$input = ltrim((string)$input, '/');
|
||||
|
||||
if (Utils::contains((string)$input, '://')) {
|
||||
@@ -65,10 +75,9 @@ abstract class Utils
|
||||
$resource = $input;
|
||||
}
|
||||
|
||||
/** @var Uri $uri */
|
||||
$uri = Grav::instance()['uri'];
|
||||
|
||||
return $resource ? rtrim($uri->rootUrl($domain), '/') . '/' . $resource : null;
|
||||
|
||||
return rtrim($uri->rootUrl($domain), '/') . '/' . ($resource ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -777,22 +786,47 @@ abstract class Utils
|
||||
*/
|
||||
public static function normalizePath($path)
|
||||
{
|
||||
$root = strpos($path, '/') === 0 ? '/' : '';
|
||||
|
||||
$segments = explode('/', trim($path, '/'));
|
||||
$ret = [];
|
||||
foreach ($segments as $segment) {
|
||||
if (($segment === '.') || $segment === '') {
|
||||
continue;
|
||||
}
|
||||
if ($segment === '..') {
|
||||
array_pop($ret);
|
||||
} else {
|
||||
$ret[] = $segment;
|
||||
}
|
||||
// Resolve any streams
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = Grav::instance()['locator'];
|
||||
if ($locator->isStream($path)) {
|
||||
$path = $locator->findResource($path);
|
||||
}
|
||||
|
||||
return $root . implode('/', $ret);
|
||||
// Set root properly for any URLs
|
||||
$root = '';
|
||||
preg_match(self::ROOTURL_REGEX, $path, $matches);
|
||||
if ($matches) {
|
||||
$root = $matches[1];
|
||||
$path = $matches[2];
|
||||
}
|
||||
|
||||
// Strip off leading / to ensure explode is accurate
|
||||
if (Utils::startsWith($path,'/')) {
|
||||
$root .= '/';
|
||||
$path = ltrim($path, '/');
|
||||
}
|
||||
|
||||
// If there are any relative paths (..) handle those
|
||||
if (Utils::contains($path, '..')) {
|
||||
$segments = explode('/', trim($path, '/'));
|
||||
$ret = [];
|
||||
foreach ($segments as $segment) {
|
||||
if (($segment === '.') || $segment === '') {
|
||||
continue;
|
||||
}
|
||||
if ($segment === '..') {
|
||||
array_pop($ret);
|
||||
} else {
|
||||
$ret[] = $segment;
|
||||
}
|
||||
}
|
||||
$path = implode('/', $ret);
|
||||
}
|
||||
|
||||
// Stick everything back together
|
||||
$normalized = $root . $path;
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1371,10 +1405,10 @@ abstract class Utils
|
||||
$unit = preg_replace('/[^bkmgtpezy]/i', '', $size);
|
||||
$size = preg_replace('/[^0-9\.]/', '', $size);
|
||||
if ($unit) {
|
||||
return (int)((int)$size * (1024 ** stripos('bkmgtpezy', $unit[0])));
|
||||
return round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
|
||||
} else {
|
||||
return round($size);
|
||||
}
|
||||
|
||||
return (int)$size;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,7 @@ use Grav\Common\Cache;
|
||||
use Grav\Console\ConsoleCommand;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class CacheCommand extends ConsoleCommand
|
||||
class ClearCacheCommand extends ConsoleCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
@@ -13,7 +13,7 @@ use Grav\Common\Cache;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Composer;
|
||||
use Grav\Common\GravTrait;
|
||||
use Grav\Console\Cli\CacheCommand;
|
||||
use Grav\Console\Cli\ClearCacheCommand;
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
@@ -107,7 +107,7 @@ trait ConsoleTrait
|
||||
$all = ['--all' => true];
|
||||
}
|
||||
|
||||
$command = new CacheCommand();
|
||||
$command = new ClearCacheCommand();
|
||||
$input = new ArrayInput($all);
|
||||
return $command->run($input, $this->output);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ class Flex implements \Countable
|
||||
*/
|
||||
public function addDirectory(FlexDirectory $directory)
|
||||
{
|
||||
$this->types[$directory->getType()] = $directory;
|
||||
$this->types[$directory->getFlexType()] = $directory;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
|
||||
parent::__construct($entries);
|
||||
|
||||
if ($directory) {
|
||||
$this->setFlexDirectory($directory)->setKey($directory->getType());
|
||||
$this->setFlexDirectory($directory)->setKey($directory->getFlexType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
|
||||
*/
|
||||
public function getFlexType(): string
|
||||
{
|
||||
return $this->_flexDirectory->getType();
|
||||
return $this->_flexDirectory->getFlexType();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -245,7 +245,7 @@ class FlexCollection extends ObjectCollection implements FlexCollectionInterface
|
||||
* {@inheritdoc}
|
||||
* @see FlexCollectionInterface::render()
|
||||
*/
|
||||
public function render($layout = null, array $context = [])
|
||||
public function render(string $layout = null, array $context = [])
|
||||
{
|
||||
if (null === $layout) {
|
||||
$layout = 'default';
|
||||
|
||||
@@ -91,8 +91,19 @@ class FlexDirectory implements FlexAuthorizeInterface
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @deprecated 1.6 Use ->getFlexType() method instead.
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use ->getFlexType() method instead', E_USER_DEPRECATED);
|
||||
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFlexType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
@@ -102,7 +113,7 @@ class FlexDirectory implements FlexAuthorizeInterface
|
||||
*/
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->getBlueprintInternal()->get('title', ucfirst($this->getType()));
|
||||
return $this->getBlueprintInternal()->get('title', ucfirst($this->getFlexType()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,13 +323,13 @@ class FlexDirectory implements FlexAuthorizeInterface
|
||||
if (Utils::isAdminPlugin()) {
|
||||
$key = substr($key, 0, -1);
|
||||
}
|
||||
$cache = new DoctrineCache($gravCache->getCacheDriver(), 'flex-objects-' . $this->getType() . $key, $timeout);
|
||||
$cache = new DoctrineCache($gravCache->getCacheDriver(), 'flex-objects-' . $this->getFlexType() . $key, $timeout);
|
||||
} catch (\Exception $e) {
|
||||
/** @var Debugger $debugger */
|
||||
$debugger = Grav::instance()['debugger'];
|
||||
$debugger->addException($e);
|
||||
|
||||
$cache = new MemoryCache('flex-objects-' . $this->getType());
|
||||
$cache = new MemoryCache('flex-objects-' . $this->getFlexType());
|
||||
}
|
||||
|
||||
// Disable cache key validation.
|
||||
|
||||
@@ -45,7 +45,7 @@ class FlexForm implements FlexFormInterface
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->form = $form;
|
||||
$uniqueId = $object->exists() ? $object->getStorageKey() : "{$object->getType()}:new";
|
||||
$uniqueId = $object->exists() ? $object->getStorageKey() : "{$object->getFlexType()}:new";
|
||||
$this->setObject($object);
|
||||
$this->setId($this->getName());
|
||||
$this->setUniqueId(md5($uniqueId));
|
||||
@@ -73,7 +73,7 @@ class FlexForm implements FlexFormInterface
|
||||
$object = $this->getObject();
|
||||
$name = $this->name ?: 'object';
|
||||
|
||||
return "flex-{$object->getType()}-{$name}";
|
||||
return "flex-{$object->getFlexType()}-{$name}";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,6 +101,26 @@ class FlexForm implements FlexFormInterface
|
||||
return $value ?? $this->getObject()->value($name);
|
||||
}
|
||||
|
||||
public function getDefaultValue(string $name)
|
||||
{
|
||||
return $this->object->getDefaultValue($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getDefaultValues(): array
|
||||
{
|
||||
return $this->object->getDefaultValues();
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFlexType(): string
|
||||
{
|
||||
return $this->object->getFlexType();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FlexObjectInterface
|
||||
*/
|
||||
|
||||
@@ -104,7 +104,7 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
|
||||
*/
|
||||
public function getFlexType(): string
|
||||
{
|
||||
return $this->_flexDirectory->getType();
|
||||
return $this->_flexDirectory->getFlexType();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,7 +171,7 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
|
||||
{
|
||||
// Get storage keys for the objects.
|
||||
$keys = [];
|
||||
$type = $this->_flexDirectory->getType() . '.obj:';
|
||||
$type = $this->_flexDirectory->getFlexType() . '.obj:';
|
||||
|
||||
foreach ($this->getEntries() as $key => $value) {
|
||||
$keys[$key] = $value['flex_key'] ?? $type . $value['storage_key'];
|
||||
@@ -191,7 +191,7 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
|
||||
return $this;
|
||||
}
|
||||
|
||||
$type = $keyField === 'flex_key' ? $this->_flexDirectory->getType() . '.obj:' : '';
|
||||
$type = $keyField === 'flex_key' ? $this->_flexDirectory->getFlexType() . '.obj:' : '';
|
||||
$entries = [];
|
||||
foreach ($this->getEntries() as $key => $value) {
|
||||
if (!isset($value['key'])) {
|
||||
@@ -221,7 +221,7 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
|
||||
* {@inheritdoc}
|
||||
* @see FlexCollectionInterface::render()
|
||||
*/
|
||||
public function render($layout = null, array $context = [])
|
||||
public function render(string $layout = null, array $context = [])
|
||||
{
|
||||
return $this->__call('render', [$layout, $context]);
|
||||
}
|
||||
@@ -583,11 +583,16 @@ class FlexIndex extends ObjectIndex implements FlexCollectionInterface, FlexInde
|
||||
$keys = array_fill_keys(array_keys($entries), null);
|
||||
$rows = $storage->readRows($keys);
|
||||
|
||||
$keyField = $storage->getKeyField();
|
||||
|
||||
// Go through all the updated objects and refresh their index data.
|
||||
$updated = $added = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
if (null !== $row) {
|
||||
$entry = ['key' => $key] + $entries[$key];
|
||||
if ($keyField !== 'storage_key' && isset($row[$keyField])) {
|
||||
$entry['key'] = $row[$keyField];
|
||||
}
|
||||
static::updateIndexData($entry, $row);
|
||||
if (isset($row['__error'])) {
|
||||
$entry['__error'] = true;
|
||||
|
||||
@@ -115,7 +115,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
*/
|
||||
public function getFlexType(): string
|
||||
{
|
||||
return $this->_flexDirectory->getType();
|
||||
return $this->_flexDirectory->getFlexType();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,7 +186,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
*/
|
||||
public function getFlexKey(): string
|
||||
{
|
||||
return $this->_storage['flex_key'] ?? $this->_flexDirectory->getType() . '.obj:' . $this->getStorageKey();
|
||||
return $this->_storage['flex_key'] ?? $this->_flexDirectory->getFlexType() . '.obj:' . $this->getStorageKey();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -357,7 +357,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
* {@inheritdoc}
|
||||
* @see FlexObjectInterface::render()
|
||||
*/
|
||||
public function render($layout = null, array $context = [])
|
||||
public function render(string $layout = null, array $context = [])
|
||||
{
|
||||
if (null === $layout) {
|
||||
$layout = 'default';
|
||||
@@ -510,7 +510,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
* {@inheritdoc}
|
||||
* @see FlexObjectInterface::create()
|
||||
*/
|
||||
public function create($key = null)
|
||||
public function create(string $key = null)
|
||||
{
|
||||
if ($key) {
|
||||
$this->setStorageKey($key);
|
||||
@@ -616,9 +616,50 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @see FlexObjectInterface::value()
|
||||
* @see FlexObjectInterface::getDefaultValue()
|
||||
*/
|
||||
public function value($name, $default = null, $separator = null)
|
||||
public function getDefaultValue(string $name, string $separator = null)
|
||||
{
|
||||
$separator = $separator ?: '.';
|
||||
$path = explode($separator, $name) ?: [];
|
||||
$offset = array_shift($path) ?? '';
|
||||
|
||||
$current = $this->getDefaultValues();
|
||||
|
||||
if (!isset($current[$offset])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$current = $current[$offset];
|
||||
|
||||
while ($path) {
|
||||
$offset = array_shift($path);
|
||||
|
||||
if ((\is_array($current) || $current instanceof \ArrayAccess) && isset($current[$offset])) {
|
||||
$current = $current[$offset];
|
||||
} elseif (\is_object($current) && isset($current->{$offset})) {
|
||||
$current = $current->{$offset};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return $current;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getDefaultValues(): array
|
||||
{
|
||||
return $this->getBlueprint()->getDefaults();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @see FlexObjectInterface::getFormValue()
|
||||
*/
|
||||
public function getFormValue(string $name, $default = null, string $separator = null)
|
||||
{
|
||||
if ($name === 'storage_key') {
|
||||
return $this->getStorageKey();
|
||||
@@ -630,6 +671,19 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
return $this->getNestedProperty($name, $default, $separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed|null $default
|
||||
* @param string|null $separator
|
||||
* @return mixed
|
||||
*
|
||||
* @deprecated 1.6 Use ->getFormValue() method instead.
|
||||
*/
|
||||
public function value($name, $default = null, $separator = null)
|
||||
{
|
||||
return $this->getFormValue($name, $default, $separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this object.
|
||||
*
|
||||
|
||||
@@ -11,11 +11,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace Grav\Framework\Flex\Interfaces;
|
||||
|
||||
use Grav\Framework\ContentBlock\ContentBlockInterface;
|
||||
use Grav\Framework\ContentBlock\HtmlBlock;
|
||||
use Grav\Framework\Flex\FlexDirectory;
|
||||
use Twig\Error\LoaderError;
|
||||
use Twig\Error\SyntaxError;
|
||||
use Grav\Framework\Interfaces\RenderInterface;
|
||||
|
||||
/**
|
||||
* Defines common interface shared with both Flex Objects and Collections.
|
||||
@@ -23,7 +20,7 @@ use Twig\Error\SyntaxError;
|
||||
* @used-by \Grav\Framework\Flex\FlexObject
|
||||
* @since 1.6
|
||||
*/
|
||||
interface FlexCommonInterface
|
||||
interface FlexCommonInterface extends RenderInterface
|
||||
{
|
||||
/**
|
||||
* Get Flex Type of the object / collection.
|
||||
@@ -64,22 +61,4 @@ interface FlexCommonInterface
|
||||
* @return string Returns cache checksum.
|
||||
*/
|
||||
public function getCacheChecksum(): string;
|
||||
|
||||
/**
|
||||
* Renders the object / collection.
|
||||
*
|
||||
* @example {% render object layout 'edit' with { limited: true } %}
|
||||
* @example {% render collection layout 'list' %}
|
||||
*
|
||||
* @param string $layout Layout name.
|
||||
* @param array $context Context given to the renderer.
|
||||
*
|
||||
* @return ContentBlockInterface|HtmlBlock Returns `HtmlBlock` containing the rendered output.
|
||||
* @throws \Exception
|
||||
* @throws \Throwable
|
||||
* @throws LoaderError
|
||||
* @throws SyntaxError
|
||||
* @api
|
||||
*/
|
||||
public function render($layout = null, array $context = []);
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ interface FlexObjectInterface extends FlexCommonInterface, NestedObjectInterface
|
||||
* @throws \RuntimeException if object already exists.
|
||||
* @api
|
||||
*/
|
||||
public function create($key = null);
|
||||
public function create(string $key = null);
|
||||
|
||||
/**
|
||||
* Save object into the storage.
|
||||
@@ -173,12 +173,36 @@ interface FlexObjectInterface extends FlexCommonInterface, NestedObjectInterface
|
||||
public function getForm(string $name = '', array $form = null);
|
||||
|
||||
/**
|
||||
* Form field compatibility.
|
||||
* Returns default value suitable to be used in a form for the given property.
|
||||
*
|
||||
* @param string $name Property name.
|
||||
* @param mixed $default Default value.
|
||||
* @param string $separator Optional nested property separator.
|
||||
* @return mixed Returns value of the field.
|
||||
* @see FlexObjectInterface::getForm()
|
||||
*
|
||||
* @param string $name Property name.
|
||||
* @param string $separator Optional nested property separator.
|
||||
*
|
||||
* @return mixed|null Returns default value of the field, null if there is no default value.
|
||||
*/
|
||||
public function value($name, $default = null, $separator = null);
|
||||
public function getDefaultValue(string $name, string $separator = null);
|
||||
|
||||
/**
|
||||
* Returns default values suitable to be used in a form for the given property.
|
||||
*
|
||||
* @see FlexObjectInterface::getForm()
|
||||
*
|
||||
* @return array Returns default values.
|
||||
*/
|
||||
public function getDefaultValues(): array;
|
||||
|
||||
/**
|
||||
* Returns raw value suitable to be used in a form for the given property.
|
||||
*
|
||||
* @see FlexObjectInterface::getForm()
|
||||
*
|
||||
* @param string $name Property name.
|
||||
* @param mixed $default Default value.
|
||||
* @param string $separator Optional nested property separator.
|
||||
*
|
||||
* @return mixed Returns value of the field.
|
||||
*/
|
||||
public function getFormValue(string $name, $default = null, string $separator = null);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@ interface FlexStorageInterface
|
||||
*/
|
||||
public function __construct(array $options);
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getKeyField(): string;
|
||||
|
||||
/**
|
||||
* Returns associated array of all existing storage keys with a timestamp.
|
||||
*
|
||||
@@ -40,6 +45,15 @@ interface FlexStorageInterface
|
||||
*/
|
||||
public function hasKey(string $key): bool;
|
||||
|
||||
/**
|
||||
* Check if the key exists in the storage.
|
||||
*
|
||||
* @param string[] $keys Storage key of an object.
|
||||
*
|
||||
* @return bool[] Returns keys with `true` if the key exists in the storage, `false` otherwise.
|
||||
*/
|
||||
public function hasKeys(array $keys): array;
|
||||
|
||||
/**
|
||||
* Create new rows into the storage.
|
||||
*
|
||||
|
||||
@@ -32,6 +32,31 @@ abstract class AbstractFilesystemStorage implements FlexStorageInterface
|
||||
{
|
||||
/** @var FileFormatterInterface */
|
||||
protected $dataFormatter;
|
||||
/** @var string */
|
||||
protected $keyField = 'storage_key';
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @see FlexStorageInterface::hasKey()
|
||||
*/
|
||||
public function hasKeys(array $keys): array
|
||||
{
|
||||
$list = [];
|
||||
foreach ($keys as $key) {
|
||||
$list[$key] = $this->hasKey((string)$key);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getKeyField(): string
|
||||
{
|
||||
return $this->keyField;
|
||||
}
|
||||
|
||||
protected function initDataFormatter($formatter): void
|
||||
{
|
||||
|
||||
@@ -71,7 +71,7 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function hasKey(string $key): bool
|
||||
{
|
||||
return $key && !strpos($key, '@@') && file_exists($this->getPathFromKey($key));
|
||||
return $key && strpos($key, '@@') === false && file_exists($this->getPathFromKey($key));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,6 +102,7 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
foreach ($rows as $key => $row) {
|
||||
if (null === $row || (!\is_object($row) && !\is_array($row))) {
|
||||
// Only load rows which haven't been loaded before.
|
||||
$key = (string)$key;
|
||||
if (!$this->hasKey($key)) {
|
||||
$list[$key] = null;
|
||||
} else {
|
||||
@@ -129,6 +130,7 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
{
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
$key = (string)$key;
|
||||
if (!$this->hasKey($key)) {
|
||||
$list[$key] = null;
|
||||
} else {
|
||||
@@ -149,6 +151,7 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
{
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
$key = (string)$key;
|
||||
if (!$this->hasKey($key)) {
|
||||
$list[$key] = null;
|
||||
} else {
|
||||
@@ -175,6 +178,7 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
{
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
$key = (string)$key;
|
||||
if (strpos($key, '@@')) {
|
||||
$key = $this->getNewKey();
|
||||
}
|
||||
@@ -456,6 +460,7 @@ class FolderStorage extends AbstractFilesystemStorage
|
||||
$this->dataFolder = $options['folder'];
|
||||
$this->prefixed = (bool)($options['prefixed'] ?? strpos($pattern, '/{KEY:2}/'));
|
||||
$this->indexed = (bool)($options['indexed'] ?? false);
|
||||
$this->keyField = $options['key'] ?? 'storage_key';
|
||||
|
||||
$pattern = preg_replace(['/{FOLDER}/', '/{KEY}/', '/{KEY:2}/'], ['%1$s', '%2$s', '%3$s'], $pattern);
|
||||
$this->dataPattern = \dirname($pattern) . '/' . basename($pattern, $extension) . $extension;
|
||||
|
||||
@@ -71,7 +71,11 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function hasKey(string $key): bool
|
||||
{
|
||||
return $key && !strpos($key, '@@') && isset($this->data[$key]);
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
return $key && strpos($key, '@@') === false && isset($this->data[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,6 +84,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function createRows(array $rows): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
$key = $this->getNewKey();
|
||||
@@ -99,10 +107,15 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function readRows(array $rows, array &$fetched = null): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
if (null === $row || (!\is_object($row) && !\is_array($row))) {
|
||||
// Only load rows which haven't been loaded before.
|
||||
$key = (string)$key;
|
||||
$list[$key] = $this->hasKey($key) ? $this->data[$key] : null;
|
||||
if (null !== $fetched) {
|
||||
$fetched[$key] = $list[$key];
|
||||
@@ -122,8 +135,13 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function updateRows(array $rows): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
$key = (string)$key;
|
||||
if ($this->hasKey($key)) {
|
||||
$this->data[$key] = $list[$key] = $row;
|
||||
}
|
||||
@@ -142,8 +160,13 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function deleteRows(array $rows): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
$key = (string)$key;
|
||||
if ($this->hasKey($key)) {
|
||||
unset($this->data[$key]);
|
||||
$list[$key] = $row;
|
||||
@@ -163,6 +186,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function replaceRows(array $rows): array
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $key => $row) {
|
||||
$this->data[$key] = $list[$key] = $row;
|
||||
@@ -181,6 +208,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
*/
|
||||
public function renameRow(string $src, string $dst): bool
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
if ($this->hasKey($dst)) {
|
||||
throw new \RuntimeException("Cannot rename object: key '{$dst}' is already taken");
|
||||
}
|
||||
@@ -218,6 +249,10 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
|
||||
protected function save() : void
|
||||
{
|
||||
if (null === $this->data) {
|
||||
$this->buildIndex();
|
||||
}
|
||||
|
||||
try {
|
||||
$file = $this->getFile($this->getStoragePath());
|
||||
$file->save($this->data);
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Grav\Framework\Flex\Traits;
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
use Grav\Common\Cache;
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Common\Grav;
|
||||
@@ -312,6 +313,13 @@ trait FlexMediaTrait
|
||||
return $file && file_exists($file) ? MediumFactory::fromFile($file) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Cache
|
||||
*/
|
||||
protected function getMediaCache()
|
||||
{
|
||||
return $this->getCache('object');
|
||||
}
|
||||
|
||||
protected function offsetLoad_media()
|
||||
{
|
||||
|
||||
@@ -390,11 +390,11 @@ class FormFlash implements \JsonSerializable
|
||||
*/
|
||||
protected function addFileInternal(?string $field, string $name, array $data, array $crop = null): void
|
||||
{
|
||||
$field = $field ?: 'undefined';
|
||||
if (!isset($this->files[$field])) {
|
||||
$this->files[$field] = [];
|
||||
}
|
||||
|
||||
$field = $field ?: 'undefined';
|
||||
$oldUpload = $this->files[$field][$name] ?? null;
|
||||
|
||||
if ($crop) {
|
||||
|
||||
@@ -16,7 +16,6 @@ use Grav\Common\Form\FormFlash;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Utils;
|
||||
use Grav\Framework\Form\Interfaces\FormInterface;
|
||||
use Grav\Framework\Session\Session;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Message\UploadedFileInterface;
|
||||
|
||||
@@ -113,6 +112,42 @@ trait FormTrait
|
||||
return $this->data[$name] ?? null;
|
||||
}
|
||||
|
||||
public function getDefaultValue(string $name)
|
||||
{
|
||||
$path = explode('.', $name) ?: [];
|
||||
$offset = array_shift($path) ?? '';
|
||||
|
||||
$current = $this->getDefaultValues();
|
||||
|
||||
if (!isset($current[$offset])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$current = $current[$offset];
|
||||
|
||||
while ($path) {
|
||||
$offset = array_shift($path);
|
||||
|
||||
if ((\is_array($current) || $current instanceof \ArrayAccess) && isset($current[$offset])) {
|
||||
$current = $current[$offset];
|
||||
} elseif (\is_object($current) && isset($current->{$offset})) {
|
||||
$current = $current->{$offset};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return $current;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getDefaultValues(): array
|
||||
{
|
||||
return $this->getBlueprint()->getDefaults();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @return FormInterface|$this
|
||||
@@ -273,24 +308,30 @@ trait FormTrait
|
||||
public function getFlash(): FormFlash
|
||||
{
|
||||
if (null === $this->flash) {
|
||||
/** @var Grav $grav */
|
||||
$grav = Grav::instance();
|
||||
$user = $grav['user'];
|
||||
$id = null;
|
||||
|
||||
$rememberState = $this->getBlueprint()->get('form/remember_state');
|
||||
if ($rememberState === 'user') {
|
||||
$id = $user->username;
|
||||
$user = $grav['user'] ?? null;
|
||||
if (isset($user)) {
|
||||
$rememberState = $this->getBlueprint()->get('form/remember_state');
|
||||
if ($rememberState === 'user') {
|
||||
$id = $user->username;
|
||||
}
|
||||
}
|
||||
|
||||
// By default store flash by the session id.
|
||||
if (null === $id) {
|
||||
/** @var Session $session */
|
||||
$session = $grav['session'];
|
||||
$id = $session->getId();
|
||||
}
|
||||
// Session Required for flash form
|
||||
$session = $grav['session'] ?? null;
|
||||
if (isset($session)) {
|
||||
// By default store flash by the session id.
|
||||
if (null === $id) {
|
||||
$id = $session->getId();
|
||||
}
|
||||
|
||||
$this->flash = new FormFlash($id, $this->getUniqueId(), $this->getName());
|
||||
$this->flash->setUrl($grav['uri']->url)->setUser($user);
|
||||
|
||||
$this->flash = new FormFlash($id, $this->getUniqueId(), $this->getName());
|
||||
$this->flash->setUrl($grav['uri']->url)->setUser($user);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->flash;
|
||||
|
||||
38
system/src/Grav/Framework/Interfaces/RenderInterface.php
Normal file
38
system/src/Grav/Framework/Interfaces/RenderInterface.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @package Grav\Framework\Interfaces
|
||||
*
|
||||
* @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Framework\Interfaces;
|
||||
|
||||
use Grav\Framework\ContentBlock\ContentBlockInterface;
|
||||
use Grav\Framework\ContentBlock\HtmlBlock;
|
||||
|
||||
/**
|
||||
* Defines common interface to render any object.
|
||||
*
|
||||
* @used-by \Grav\Framework\Flex\FlexObject
|
||||
* @since 1.6
|
||||
*/
|
||||
interface RenderInterface
|
||||
{
|
||||
/**
|
||||
* Renders the object.
|
||||
*
|
||||
* @example $block = $object->render('custom', ['variable' => 'value']);
|
||||
* @example {% render object layout 'custom' with { variable: 'value' } %}
|
||||
*
|
||||
* @param string|null $layout Layout to be used.
|
||||
* @param array|null $context Extra context given to the renderer.
|
||||
*
|
||||
* @return ContentBlockInterface|HtmlBlock Returns `HtmlBlock` containing the rendered output.
|
||||
* @api
|
||||
*/
|
||||
public function render(string $layout = null, array $context = []);
|
||||
}
|
||||
@@ -95,7 +95,7 @@ trait ArrayPropertyTrait
|
||||
*/
|
||||
protected function getElements()
|
||||
{
|
||||
return $this->_elements;
|
||||
return array_filter($this->_elements, function ($val) { return $val !== null; });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -183,7 +183,10 @@ trait ObjectPropertyTrait
|
||||
|
||||
$elements = [];
|
||||
foreach ($properties as $offset => $value) {
|
||||
$elements[$offset] = $this->offsetSerialize($offset, $value);
|
||||
$serialized = $this->offsetSerialize($offset, $value);
|
||||
if ($serialized !== null) {
|
||||
$elements[$offset] = $this->offsetSerialize($offset, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return $elements;
|
||||
|
||||
@@ -15,6 +15,9 @@ use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class NotFoundException extends RequestException
|
||||
{
|
||||
/** @var ServerRequestInterface */
|
||||
private $request;
|
||||
|
||||
/**
|
||||
* NotFoundException constructor.
|
||||
* @param ServerRequestInterface $request
|
||||
@@ -28,4 +31,9 @@ class NotFoundException extends RequestException
|
||||
parent::__construct($request, 'Not Found', 404, $previous);
|
||||
}
|
||||
}
|
||||
|
||||
public function getRequest(): ServerRequestInterface
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class Exceptions implements MiddlewareInterface
|
||||
{
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
try {
|
||||
return $handler->handle($request);
|
||||
@@ -38,7 +38,7 @@ class Exceptions implements MiddlewareInterface
|
||||
/** @var string $json */
|
||||
$json = json_encode($response);
|
||||
|
||||
return new Response($exception->getCode() ?: 500, [], $json);
|
||||
return new Response($exception->getCode() ?: 500, ['Content-Type' => 'application/json'], $json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ class AssetsTest extends \Codeception\TestCase\Test
|
||||
"type":"text\/css",
|
||||
"rel":"stylesheet"
|
||||
},
|
||||
"timestamp":null,
|
||||
"modified":false,
|
||||
"query":""
|
||||
}
|
||||
@@ -82,7 +81,6 @@ class AssetsTest extends \Codeception\TestCase\Test
|
||||
"attributes":[
|
||||
|
||||
],
|
||||
"timestamp":null,
|
||||
"modified":false,
|
||||
"query":""
|
||||
}
|
||||
@@ -113,7 +111,6 @@ class AssetsTest extends \Codeception\TestCase\Test
|
||||
"type":"text\/css",
|
||||
"rel":"stylesheet"
|
||||
},
|
||||
"timestamp":null,
|
||||
"modified":false,
|
||||
"query":""
|
||||
}
|
||||
@@ -144,8 +141,6 @@ class AssetsTest extends \Codeception\TestCase\Test
|
||||
"type":"text\/css",
|
||||
"rel":"stylesheet"
|
||||
},
|
||||
"timestamp":null,
|
||||
"modified":null,
|
||||
"query":""
|
||||
}
|
||||
}';
|
||||
@@ -178,7 +173,6 @@ class AssetsTest extends \Codeception\TestCase\Test
|
||||
"position":"pipeline",
|
||||
"priority":10,
|
||||
"attributes":[],
|
||||
"timestamp":null,
|
||||
"modified":false,
|
||||
"query":""
|
||||
}
|
||||
@@ -211,7 +205,6 @@ class AssetsTest extends \Codeception\TestCase\Test
|
||||
"type": "text/css",
|
||||
"rel": "stylesheet"
|
||||
},
|
||||
"timestamp": null,
|
||||
"modified": false,
|
||||
"query": ""
|
||||
}
|
||||
@@ -242,7 +235,6 @@ class AssetsTest extends \Codeception\TestCase\Test
|
||||
"position": "pipeline",
|
||||
"priority": 10,
|
||||
"attributes": [],
|
||||
"timestamp": null,
|
||||
"modified": false,
|
||||
"query": ""
|
||||
}
|
||||
@@ -272,7 +264,6 @@ class AssetsTest extends \Codeception\TestCase\Test
|
||||
"attributes": {
|
||||
"loading": "async"
|
||||
},
|
||||
"timestamp": null,
|
||||
"modified": false,
|
||||
"query": ""
|
||||
}
|
||||
@@ -301,7 +292,6 @@ class AssetsTest extends \Codeception\TestCase\Test
|
||||
"attributes": {
|
||||
"loading": "defer"
|
||||
},
|
||||
"timestamp": null,
|
||||
"modified": false,
|
||||
"query": ""
|
||||
}
|
||||
@@ -410,7 +400,6 @@ class AssetsTest extends \Codeception\TestCase\Test
|
||||
"rel":"stylesheet",
|
||||
"loading":"async"
|
||||
},
|
||||
"timestamp":null,
|
||||
"modified":false,
|
||||
"query":""
|
||||
}
|
||||
@@ -439,7 +428,6 @@ class AssetsTest extends \Codeception\TestCase\Test
|
||||
"attributes": {
|
||||
"loading": "defer"
|
||||
},
|
||||
"timestamp": null,
|
||||
"modified": false,
|
||||
"query": ""
|
||||
}
|
||||
|
||||
@@ -573,7 +573,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => 'html',
|
||||
'addNonce' => 'http://localhost/a-page.html/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/a-page', // FIXME <-
|
||||
'__toString' => 'http://localhost/a-page.html',
|
||||
],
|
||||
'http://localhost/a-page.json' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -596,7 +596,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => 'json',
|
||||
'addNonce' => 'http://localhost/a-page.json/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/a-page', // FIX ME <-
|
||||
'__toString' => 'http://localhost/a-page.json',
|
||||
],
|
||||
'http://localhost/admin/ajax.json/task:getnewsfeed' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -619,7 +619,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => 'json',
|
||||
'addNonce' => 'http://localhost/admin/ajax.json/task:getnewsfeed/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/admin/ajax/task:getnewsfeed',
|
||||
'__toString' => 'http://localhost/admin/ajax.json/task:getnewsfeed',
|
||||
],
|
||||
'http://localhost/grav/admin/media.json/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -642,7 +642,7 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
'rootUrl' => 'http://localhost',
|
||||
'extension' => 'json',
|
||||
'addNonce' => 'http://localhost/grav/admin/media.json/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==/nonce:{{nonce}}',
|
||||
'__toString' => 'http://localhost/grav/admin/media/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==', // FIXME <-
|
||||
'__toString' => 'http://localhost/grav/admin/media.json/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==',
|
||||
],
|
||||
'http://localhost/a-page.foo' => [
|
||||
'scheme' => 'http://',
|
||||
@@ -1121,6 +1121,24 @@ class UriTest extends \Codeception\TestCase\Test
|
||||
];
|
||||
|
||||
$this->assertSame('http://foo:bar@localhost:8080/test?x=2#xxx', Uri::buildUrl($parsed_url));
|
||||
|
||||
/** @var Uri $uri */
|
||||
$uri = Grav::instance()['uri'];
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html', '/subdir')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.html', Uri::buildUrl($uri->toArray()));
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.foo', '/subdir')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.foo', Uri::buildUrl($uri->toArray()));
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html', '/subdir/path1')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.html', Uri::buildUrl($uri->toArray()));
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom', '/subdir')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom', Uri::buildUrl($uri->toArray()));
|
||||
|
||||
$uri->initializeWithUrlAndRootPath('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom?fig=something', '/subdir')->init();
|
||||
$this->assertSame('https://testing.dev/subdir/path1/path2/file.html/foo:blah/bang:boom?fig=something', Uri::buildUrl($uri->toArray()));
|
||||
}
|
||||
|
||||
public function testConvertUrl()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use Codeception\Util\Fixtures;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Uri;
|
||||
use Grav\Common\Utils;
|
||||
|
||||
/**
|
||||
@@ -12,10 +13,14 @@ class UtilsTest extends \Codeception\TestCase\Test
|
||||
/** @var Grav $grav */
|
||||
protected $grav;
|
||||
|
||||
/** @var Uri $uri */
|
||||
protected $uri;
|
||||
|
||||
protected function _before()
|
||||
{
|
||||
$grav = Fixtures::get('grav');
|
||||
$this->grav = $grav();
|
||||
$this->uri = $this->grav['uri'];
|
||||
}
|
||||
|
||||
protected function _after()
|
||||
@@ -146,6 +151,8 @@ class UtilsTest extends \Codeception\TestCase\Test
|
||||
|
||||
public function testTruncateHtml()
|
||||
{
|
||||
$this->assertEquals('T...', Utils::truncateHtml('This is a string to truncate', 1));
|
||||
$this->assertEquals('This is...', Utils::truncateHtml('This is a string to truncate', 7));
|
||||
$this->assertEquals('<p>T...</p>', Utils::truncateHtml('<p>This is a string to truncate</p>', 1));
|
||||
$this->assertEquals('<p>This...</p>', Utils::truncateHtml('<p>This is a string to truncate</p>', 4));
|
||||
$this->assertEquals('<p>This is a...</p>', Utils::truncateHtml('<p>This is a string to truncate</p>', 10));
|
||||
@@ -157,6 +164,8 @@ class UtilsTest extends \Codeception\TestCase\Test
|
||||
|
||||
public function testSafeTruncateHtml()
|
||||
{
|
||||
$this->assertEquals('This...', Utils::safeTruncateHtml('This is a string to truncate', 1));
|
||||
$this->assertEquals('This is a...', Utils::safeTruncateHtml('This is a string to truncate', 3));
|
||||
$this->assertEquals('<p>This...</p>', Utils::safeTruncateHtml('<p>This is a string to truncate</p>', 1));
|
||||
$this->assertEquals('<p>This is...</p>', Utils::safeTruncateHtml('<p>This is a string to truncate</p>', 2));
|
||||
$this->assertEquals('<p>This is a string to...</p>', Utils::safeTruncateHtml('<p>This is a string to truncate</p>', 5));
|
||||
@@ -215,7 +224,19 @@ class UtilsTest extends \Codeception\TestCase\Test
|
||||
$this->assertEquals('test', Utils::normalizePath('../test'));
|
||||
$this->assertEquals('/test', Utils::normalizePath('/../test'));
|
||||
$this->assertEquals('/test2', Utils::normalizePath('/test/../test2'));
|
||||
$this->assertEquals('/test/test2', Utils::normalizePath('/test/./test2'));
|
||||
$this->assertEquals('/test3', Utils::normalizePath('/test/../test2/../test3'));
|
||||
|
||||
$this->assertEquals('//cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('//cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css'));
|
||||
$this->assertEquals('//use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('//use.fontawesome.com/releases/v5.8.1/css/all.css'));
|
||||
$this->assertEquals('//use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('//use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot'));
|
||||
|
||||
$this->assertEquals('http://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('http://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css'));
|
||||
$this->assertEquals('http://use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('http://use.fontawesome.com/releases/v5.8.1/css/all.css'));
|
||||
$this->assertEquals('http://use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('http://use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot'));
|
||||
|
||||
$this->assertEquals('https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css'));
|
||||
$this->assertEquals('https://use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('https://use.fontawesome.com/releases/v5.8.1/css/all.css'));
|
||||
$this->assertEquals('https://use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('https://use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot'));
|
||||
}
|
||||
|
||||
public function testIsFunctionDisabled()
|
||||
@@ -353,4 +374,65 @@ class UtilsTest extends \Codeception\TestCase\Test
|
||||
{
|
||||
$this->assertTrue(Utils::verifyNonce(Utils::getNonce('test-action'), 'test-action'));
|
||||
}
|
||||
|
||||
public function testUrl()
|
||||
{
|
||||
$this->uri->initializeWithUrl('http://testing.dev/path1/path2')->init();
|
||||
|
||||
$this->assertSame('http://testing.dev/', Utils::url('/', true));
|
||||
$this->assertSame('http://testing.dev/', Utils::url('', true));
|
||||
$this->assertSame('http://testing.dev/path1', Utils::url('/path1', true));
|
||||
$this->assertSame('/', Utils::url('/'));
|
||||
$this->assertSame('/', Utils::url(''));
|
||||
$this->assertSame('/path1', Utils::url('/path1'));
|
||||
$this->assertSame('/path1/path2', Utils::url('/path1/path2'));
|
||||
|
||||
$this->assertSame('http://testing.dev/foobar.jpg', Utils::url('foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/foobar.jpg', Utils::url('/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/path1/foobar.jpg', Utils::url('/path1/foobar.jpg', true));
|
||||
$this->assertSame('/foobar.jpg', Utils::url('/foobar.jpg'));
|
||||
$this->assertSame('/foobar.jpg', Utils::url('foobar.jpg'));
|
||||
$this->assertSame('/path1/foobar.jpg', Utils::url('/path1/foobar.jpg'));
|
||||
$this->assertSame('/path1/path2/foobar.jpg', Utils::url('/path1/path2/foobar.jpg'));
|
||||
}
|
||||
|
||||
public function testUrlWithRoot()
|
||||
{
|
||||
$this->uri->initializeWithUrlAndRootPath('http://testing.dev/subdir/path1/path2', '/subdir')->init();
|
||||
|
||||
$this->assertSame('http://testing.dev/subdir/', Utils::url('/', true));
|
||||
$this->assertSame('http://testing.dev/subdir/', Utils::url('', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1', Utils::url('/path1', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1', Utils::url('/subdir/path1', true));
|
||||
$this->assertSame('/subdir/', Utils::url('/'));
|
||||
$this->assertSame('/subdir/', Utils::url(''));
|
||||
$this->assertSame('/subdir/path1', Utils::url('/path1'));
|
||||
$this->assertSame('/subdir/path1/path2', Utils::url('/path1/path2'));
|
||||
$this->assertSame('/subdir/path1/path2', Utils::url('/subdir/path1/path2'));
|
||||
|
||||
$this->assertSame('http://testing.dev/subdir/foobar.jpg', Utils::url('foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/subdir/foobar.jpg', Utils::url('/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/subdir/foobar.jpg', Utils::url('/subdir/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1/foobar.jpg', Utils::url('/path1/foobar.jpg', true));
|
||||
$this->assertSame('http://testing.dev/subdir/path1/foobar.jpg', Utils::url('/subdir/path1/foobar.jpg', true));
|
||||
$this->assertSame('/subdir/foobar.jpg', Utils::url('/foobar.jpg'));
|
||||
$this->assertSame('/subdir/foobar.jpg', Utils::url('foobar.jpg'));
|
||||
$this->assertSame('/subdir/foobar.jpg', Utils::url('/subdir/foobar.jpg'));
|
||||
$this->assertSame('/subdir/path1/foobar.jpg', Utils::url('/path1/foobar.jpg'));
|
||||
$this->assertSame('/subdir/path1/foobar.jpg', Utils::url('/subdir/path1/foobar.jpg'));
|
||||
}
|
||||
|
||||
public function testUrlWithStreams()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function testUrlwithExternals()
|
||||
{
|
||||
$this->uri->initializeWithUrl('http://testing.dev/path1/path2')->init();
|
||||
$this->assertSame('http://foo.com', Utils::url('http://foo.com'));
|
||||
$this->assertSame('https://foo.com', Utils::url('https://foo.com'));
|
||||
$this->assertSame('//foo.com', Utils::url('//foo.com'));
|
||||
$this->assertSame('//foo.com?param=x', Utils::url('//foo.com?param=x'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,5 +41,5 @@ debugger:
|
||||
shutdown:
|
||||
close_connection: true
|
||||
gpm:
|
||||
releases: testing
|
||||
releases: stable
|
||||
verify_peer: true
|
||||
|
||||
Reference in New Issue
Block a user